Efficient way to generate a random alphabet string? - ios

I want a string of all the characters of the alphabet randomized. Right now, I create a mutable array of the 26 characters, shuffle them with the exchangeObjectAtIndex: method and then add each character to a string that I return.
There has to be a better way to do this. Here is my code:
- (NSString *)shuffledAlphabet {
NSMutableArray * shuffledAlphabet = [NSMutableArray arrayWithArray:#[#"A",#"B",#"C",#"D",#"E",#"F",#"G",#"H",#"I",#"J",#"K",#"L",#"M",#"N",#"O",#"P",#"Q",#"R",#"S",#"T",#"U",#"V",#"W",#"X",#"Y",#"Z"]];
for (NSUInteger i = 0; i < [shuffledAlphabet count]; ++i) {
// Select a random element between i and end of array to swap with.
int nElements = [shuffledAlphabet count] - i;
int n = (random() % nElements) + i;
[shuffledAlphabet exchangeObjectAtIndex:i withObjectAtIndex:n];
}
NSString *string = [[NSString alloc] init];
for (NSString *letter in shuffledAlphabet) {
string = [NSString stringWithFormat:#"%#%#",string,letter];
}
return string;
}

Here's an efficient Fisher-Yates shuffle, adapted to your use case:
- (NSString *)shuffledAlphabet {
NSString *alphabet = #"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// Get the characters into a C array for efficient shuffling
NSUInteger numberOfCharacters = [alphabet length];
unichar *characters = calloc(numberOfCharacters, sizeof(unichar));
[alphabet getCharacters:characters range:NSMakeRange(0, numberOfCharacters)];
// Perform a Fisher-Yates shuffle
for (NSUInteger i = 0; i < numberOfCharacters; ++i) {
NSUInteger j = (arc4random_uniform(numberOfCharacters - i) + i);
unichar c = characters[i];
characters[i] = characters[j];
characters[j] = c;
}
// Turn the result back into a string
NSString *result = [NSString stringWithCharacters:characters length:numberOfCharacters];
free(characters);
return result;
}

This is the more efficient way to perform a correctly shuffled alphabet generation.
- (NSString *)shuffledAlphabet
{
const NSUInteger length = 'Z' - 'A' + 1;
unichar alphabet[length];
alphabet[0] = 'A';
for ( NSUInteger i = 1; i < length; i++ )
{
NSUInteger j = arc4random_uniform((uint32_t)i + 1);
alphabet[i] = alphabet[j];
alphabet[j] = 'A' + i;
}
return [NSString stringWithCharacters:alphabet length:length];
}
It uses the "inside-out" version of the Fischer Yates shuffle and avoids modula bias by generating the pseudorandom numbers with arc4random_uniform. Also, it requires a single allocation as all the permutations are performed in a temporary buffer.

Generating random numbers in Objective-C does this help?
*generate random number
*divide by 26 and take reminder
*index array[reminder]

You could pick random elements from the (remaining) alphabet while you build your string instead of shuffling it first:
NSMutableArray *alphabet = [NSMutableArray arrayWithObjects:#"A",#"B",#"C",#"D",#"E",#"F",#"G",#"H",#"I",#"J",#"K",#"L",#"M",#"N",#"O",#"P",#"Q",#"R",#"S",#"T",#"U",#"V",#"W",#"X",#"Y",#"Z", nil];
NSMutableString *result = [NSMutableString string];
NSUInteger numberOfLetters = alphabet.count;
for (NSUInteger i = 0; i < numberOfLetters; i++) {
int n = arc4random() % alphabet.count;
[result appendString:[alphabet objectAtIndex:n]];
[alphabet removeObjectAtIndex:n];
}
NSLog(#"%#", result);
This makes the code a bit shorter. Note also that using NSMutableString is more efficient than creating a new NSString each time a letter is added.

Related

Addition with leading zeros in number

I am receiving data in the form of a string from a database like so:
NSString *strTemp = #"000014";
I need to add 1 to the above,
like 000014 + 1 = 000015
000015 + 1 = 000016
depending on some count.
like:
for(int i =1; i < 5; i++)
{
int iTemp = [strTemp intValue] +i; // here i am getting 15 as int no not like 000015, 000016, 000017 ETC
}
I even tried NSString *strWarNo = [NSString stringWithFormat:#"%07d", iTemp]; but leading numbers may not be constant ...like string from db will be anything #"0023" or #"0000056".
I need to add one to while number, not only integer number.
How I can achieve this?
You can have a category over NSString to achieve this. I tried following code and its working fine.
.h of the category
#import <Foundation/Foundation.h>
#interface NSString (Arithematic)
- (NSString*)stringByAddingNumber:(NSInteger)number;
#end
.m of the category
#import "NSString+Arithematic.h"
#implementation NSString (Arithematic)
- (NSString*)stringByAddingNumber:(NSInteger)number
{
//To keep the width same as original string
int numberLength = (int)self.length;
NSInteger originalNumber = self.integerValue;
originalNumber += number;
NSString *resultString = [NSString stringWithFormat:#"%0*ld",numberLength,originalNumber];
return resultString;
}
#end
Usage:
NSString *strTemp = #"000014";
for(int i =1; i < 5; i++)
{
strTemp = [strTemp stringByAddingNumber:i];
}
NSLog(#"result %#",strTemp);
Hope this helps.
There is a simple way of doing this by converting string into NSInteger and then add your desired value into it and then convert the integer into string by appending you desired amount of zeros before then number.
-(NSString *)addNumber:(NSInteger)number toMyString:(NSString)myNum{
NSInteger numb = myString.integerValue;
numb += myNum;
NSString myNewString = [NSString stringWithFormat:#"0%d",myNewString];
return myNum;
}
If you want to format numbers with leading zeros then use NSNumberFormatter.
Store the number as a number (not a String) and then treat it like a number.
When you need to display it use an NSNumberFormatter to add leading zeros.
You can read more about NSNumberFormatter and adding leading zeros here... NSNumberFormatter leading 0's and decimals
Add which number you have to add in "num" and pass your number string "strNumber"
EX . [self addNumber:10 andYourString:#"000014"];
-(void)addNumber:(int)num andYourString:(NSString *)strNumber {
NSString * str_your_number = strNumber;
NSString * prevous_char = [NSString stringWithFormat:#"%c",
[str_your_number characterAtIndex:0]];
int number_zero = 0;
BOOL is_leading_zero = true;
for(int i = 0 ; i < str_your_number.length ; i++){
NSString *theCharacter = [NSString stringWithFormat:#"%c", [str_your_number characterAtIndex:i]];
if(is_leading_zero == true){
if([prevous_char isEqualToString:theCharacter]) {
number_zero++;
prevous_char = theCharacter;
}
else {
is_leading_zero = false;
}
}
NSLog(#"%#",theCharacter);
}
NSLog(#"%d",number_zero);
NSInteger you_numb = strNumber.integerValue;
you_numb += num;
NSString * str_zero = #"";
for(int j = 0 ; j < number_zero ; j++) {
str_zero = [str_zero stringByAppendingString:#"0"];
}
NSString * final_str = [NSString stringWithFormat:#"%#%ld",str_zero,(long)you_numb];
NSLog(#"%#",final_str);
}
it work...

How to convert a NSString to NSInteger with the sum of ASCII values?

In my Objective-C code I'd like to take a NSString value, iterate through the letters, sum ASCII values of the letters and return that to the user (preferably as the NSString too).
I have already written a loop, but I don't know how to get the ASCII value of an individual character. What am I missing?
- (NSString*) getAsciiSum: (NSString*) input {
NSInteger sum = 0;
for (NSInteger index=0; index<input.length; index++) {
sum = sum + (NSInteger)[input characterAtIndex:index];
}
return [NSString stringWithFormat: #"%#", sum];
}
Note: I've seen similar questions related to obtaining ASCII values, but all of them ended up displaying the value as a string. I still don't know how to get ASCII value as NSInteger.
Here is the answer:
- (NSString *) getAsciiSum: (NSString *) input
{
NSString *input = #"hi";
int sum = 0;
for (NSInteger index = 0; index < input.length; index++)
{
char c = [input characterAtIndex:index];
sum = sum + c;
}
return [NSString stringWithFormat: #"%d", sum]);
}
This is working for me.
Hope this helps!
This should work.
- (NSInteger)getAsciiSum:(NSString *)stringToSum {
int asciiSum = 0;
for (int i = 0; i < stringToSum.length; i++) {
NSString *character = [stringToSum substringWithRange:NSMakeRange(i, 1)];
int asciiValue = [character characterAtIndex:0];
asciiSum = asciiSum + asciiValue;
}
return asciiSum;
}
Thank you to How to convert a NSString to NSInteger with the sum of ASCII values? for the reference.

Specific color from string

i have a uitableview, which gets populated by a pulling data from a website, so there is a new string for every cell. To that, i want to have show a HEX for the user, based on the text in the cell.
I have tryed myself to make it, without luck, but luckly found a javascript script which does what i try to do. This script, i now need to convert to obj-c, i have tryed it myself, but failed. I hope to get some help.
javascript: http://jsfiddle.net/sUK45/
My try in obj-c (here the strings aint based on the data from the web, but just an array):
unichar hash = 0;
NSArray *strings = [NSArray arrayWithObjects:#"MA", #"Ty", #"Ad", #"ER", nil];
for (int i = 0; i < [[strings objectAtIndex:indexPath.row] length]; i++) {
hash = [[strings objectAtIndex:indexPath.row] characterAtIndex:i] + ((hash < 5) - hash);
}
NSString *colour = #"#";
for (int i = 0; i < 3; i++) {
int value = (hash >> (i * 8)) & 0xFF;
colour = [NSString stringWithFormat:#"%#%d", colour, value];
}
NSLog(#"%#", colour);
But the data i get, aint a useable HEX - NSlog:
#2432550
#3600
#3400
#1200
Probably this is not the only one mistake. Change
hash = [[strings objectAtIndex:indexPath.row] characterAtIndex:i] + ((hash < 5) - hash);
to
hash = [[strings objectAtIndex:indexPath.row] characterAtIndex:i] + ((hash << 5) - hash);
UPDATE:
Also change
colour = [NSString stringWithFormat:#"%#%d", colour, value];
to
colour = [NSString stringWithFormat:#"%#%02x", colour, (unsigned int)value];
UPDATE2:
I have fixed one more error and simplified code:
unsigned int hash = 0;
NSArray *strings = [NSArray arrayWithObjects:#"MA", #"Ty", #"Ad", #"ER", nil];
NSString *string = [strings objectAtIndex:indexPath.row];
for (int i = 0; i < string.length; i++) {
hash = [string characterAtIndex:i] + ((hash << 5) - hash);
}
NSString *color = [NSString stringWithFormat:#"#%06x", hash % 0x1000000];
NSLog(#"%#", color);

Generate different random operator on two variables in objective-c/iOS

I took two labels & generating random operators on them with this code:
NSArray *operators = #[#"+", #"-", #"*", #"/"];
int randomOperatorIndex = arc4random_uniform(4);
NSString *randomOperator = operators[randomOperatorIndex];
But the both of the label are generating same random operator. I want to generate different operators on the 2 labels.
Such as:
If label-1 generates "+"
then label-2 should generate "/"
But now label-1 & label-2 have same operator after generating random operator.
How can i do this on iOS with Objective-C ?
Try this:
// Returns an array of unique random numbers with range
-(NSMutableArray *)getRandomNumbersOfSize:(int) size from:(int) lowerLimit to:(int) higherLimit
{
NSMutableArray *uniqueNumbers = [[NSMutableArray alloc] init];
int r;
while ([uniqueNumbers count] < size)
{
r = lowerLimit + arc4random_uniform(higherLimit - lowerLimit + 1) ;
if (![uniqueNumbers containsObject:[NSNumber numberWithInt:r]])
{
[uniqueNumbers addObject:[NSNumber numberWithInt:r]];
}
}
return uniqueNumbers;
}
And in your method where you need the unique random labels:
NSArray *operators = #[#"+", #"-", #"*", #"/"];
NSMutableArray* randomOperatorIndexArray = [self getRandomNumbersOfSize:2
from:0
to:([operators count]-1)];
for(int j=0;j<[randomOperatorIndexArray count];j++)
{
NSString *randomOperator = [operators objectAtIndex:[[randomOperatorIndexArray objectAtIndex:j] intValue]];
NSLog(#"%#",randomOperator);
}

Appending zeros to the end of an NSString?

I am having trouble with some code. I narrowed it down to this problem: first of all, reverseString and 2 are both NSMutableStrings _input1 and _input2 are NSStrings, i'm trying to add zeros to the smallest string but it's not working correctly, this is what I got. reverseString is #"123" and reverseString2 is #"34567".
//they get initialized back into the original strings
_input1=reversedString;
_input2=reversedString2;
//appends 0 to the shortest value
while ([_input1 length]>[_input2 length]){
_input2=[_input2 stringByAppendingString:#"0"];
_length=[_input1 length];
}
while ([_input1 length]<[_input2 length]){
_input1=[_input1 stringByAppendingString:#"0"];
_length=[_input2 length];
}
//converts the string to an NSArray
for (int i=0; i <([_input1 length]); i++) {
NSString *TempStr = [_input1 substringWithRange:NSMakeRange(i, 1)];
[one addObject:[TempStr stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
}
for (int i=0; i <([_input2 length]); i++) {
NSString *TempStr2 = [_input2 substringWithRange:NSMakeRange(i, 1)];
[two addObject:[TempStr2 stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
}
Now I noticed that when it goes through this loop, the smallest one, _input1, gets set to #"" instead of adding zeros to the end. This is within a class, by the way.
This is also an error I receive:
objc[2291]: Method cache corrupted. This may be a message to an invalid object, or a memory error somewhere else.
objc[2291]: receiver 0x100300830, SEL 0x7fff8a689779, isa 0x7fff727b8bd0, cache 0x7fff727b8be0, buckets 0x7fff89b9b09c, mask 0x1, occupied 0x0, wrap bucket 0x7fff89b9b09c
objc[2291]: receiver 0 bytes, buckets 0 bytes
objc[2291]: selector 'length'
(lldb)
Just try with following code
if([_input1 length] > [_input2 length])
{
for (int i = 0 ; i < [_input1 length] - [_input2 length] ; i ++)
_input2 = [_input2 stringByAppendingString:#"0"];
}
else
{
for (int i = 0 ; i < [_input2 length] - [_input1 length] ; i ++)
_input1 = [_input1 stringByAppendingString:#"0"];
}
Try like this:-
NSString *input1=#"123";
NSString * input2=#"34567";
NSMutableArray *one=[NSMutableArray array];
NSMutableArray *two=[NSMutableArray array];
//appends 0 to the shortest value
while ([input1 length]>[input2 length]){
input2=[input2 stringByAppendingString:#"0"];
//length=[input1 length];
}
while ([input1 length]<[input2 length]){
input1=[input1 stringByAppendingString:#"0"];
// length=[input2 length];
}
for (int i=0; i <([input1 length]); i++) {
NSString *TempStr = [input1 substringWithRange:NSMakeRange(i, 1)];
[one addObject:[TempStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
}
NSLog(#"%ld",[one count]);
for (int i=0; i <([input2 length]); i++) {
NSString *TempStr2 = [input2 substringWithRange:NSMakeRange(i, 1)];
[two addObject:[TempStr2 stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
}
NSLog(#"%ld",[two count]);
Well your requirements are not very clear, but here's a cleaner version of the code you proposed
NSString *string1 = #"foo";
NSString *string2 = #"foobar";
// Compute the desired length
NSUInteger length = MAX(string1.length, string2.length);
// We will pad using this string
NSString *paddingString = #"0";
// Pad both strings to the same length
string1 = [string1 stringByPaddingToLength:length withString:paddingString startingAtIndex:0];
string2 = [string2 stringByPaddingToLength:length withString:paddingString startingAtIndex:0];
// Build two arrays containing the characters, percent escaped
NSMutableArray *charactersArray1 = [NSMutableArray arrayWithCapacity:string1.length];
NSMutableArray *charactersArray2 = [NSMutableArray arrayWithCapacity:string2.length];
for (NSInteger i = 0; i < string1.length; i++) {
[charactersArray1 addObject:[[string1 substringWithRange:(NSRange){ i, 1 }] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
[charactersArray2 addObject:[[string2 substringWithRange:(NSRange){ i, 1 }] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
}
NSLog(#"String 1: %#\nString 2: %#", charactersArray1, charactersArray2);
The result will be
String 1: [ f, o, o, 0, 0, 0 ]
String 2: [ f, o, o, b, a, r ]
I figured out my problem, _input1 and _input2 were bad pointers and i had to fix it, sorry for all the confusion, in the end i got my code to work!

Resources