-1

i made a random for A-Z. The random letter is shown in a label. everything works fine. But the letter should not repeat till every letter from A-Z is called. I´am new in xcode an need a litte help. heres my code in the .m file.

NSString *letters = @"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-(NSString *) randomStringWithLength:(int) len {

NSMutableString *randomString = [NSMutableString stringWithCapacity: len];

for (int i=26; i<len; i++) {
    [randomString appendFormat: @"%C", [letters characterAtIndex: arc4random() % [letters length]]]; buchstabeAusgabe.text = randomString;
}

return randomString;}



-(void)neuerGenerator {

int text = rand() %26;

switch (text) {
    case 0:
        buchstabeAusgabe.text =@"A";
        break;
    case 1:
        buchstabeAusgabe.text =@"B";
        break;
    case 2:
        buchstabeAusgabe.text =@"C";
        break;
    case 3:
        buchstabeAusgabe.text =@"D";
        break;
    case 4:
        buchstabeAusgabe.text =@"E";
        break;
    case 5:
        buchstabeAusgabe.text =@"F";
        break;
    case 6:
        buchstabeAusgabe.text =@"G";
        break;
    case 7:
        buchstabeAusgabe.text =@"H";
        break;
    case 8:
        buchstabeAusgabe.text =@"I";
        break;
    case 9:
        buchstabeAusgabe.text =@"J";
        break;
    case 10:
        buchstabeAusgabe.text =@"K";
        break;
    case 11:
        buchstabeAusgabe.text =@"L";
        break;
    case 12:
        buchstabeAusgabe.text =@"M";
        break;
    case 13:
        buchstabeAusgabe.text =@"N";
        break;
    case 14:
        buchstabeAusgabe.text =@"O";
        break;
    case 15:
        buchstabeAusgabe.text =@"P";
        break;
    case 16:
        buchstabeAusgabe.text =@"Q";
        break;
    case 17:
        buchstabeAusgabe.text =@"R";
        break;
    case 18:
        buchstabeAusgabe.text =@"S";
        break;
    case 19:
        buchstabeAusgabe.text =@"T";
        break;
    case 20:
        buchstabeAusgabe.text =@"U";
        break;
    case 21:
        buchstabeAusgabe.text =@"V";
        break;
    case 22:
        buchstabeAusgabe.text =@"W";
        break;
    case 23:
        buchstabeAusgabe.text =@"X";
        break;
    case 24:
        buchstabeAusgabe.text =@"Y";
        break;
    case 25:
        buchstabeAusgabe.text =@"Z";
        break;

    default:
        break;
}}
rmaddy
  • 314,917
  • 42
  • 532
  • 579
euleec7
  • 55
  • 1
  • 6

4 Answers4

1

instead of the switch, perhaps store the alphabet in an NSMutableArray. When a letter is taken, remove it from the array. Instead of %26 do %[array count]. To look up the item in array, use [array objectAtIndex:index] where index is the random number.

I am not on XCode at the moment, but I'll try to write out the full code:

- (NSString *) randomStringWithLength:(int) len andAlphabet: (NSString *) alphabet {
    NSMutableArray *alphabetArrayMut = [[self arrayFromString: alphabet] mutableCopy];
    NSMutableString *resultString = [NSMutableString stringWithString:@""];
    while([alphabetArrayMut count]&&[resultString length]<len){
        int index = rand() % [alphabetArrayMut count];
        NSString *charToAdd = [alphabetArrayMut objectAtIndex:index];
        [resultString appendString:charToAdd];
        [alphabetArrayMut removeObjectAtIndex:index];
    }
    return [resultString copy];
}

- (NSArray *) arrayFromString: (NSString *) string{
    NSMutableArray *characters = [[NSMutableArray alloc] initWithCapacity:[string length]];
    for (int i=0; i < [string length]; i++) {
        NSString *ichar  = [NSString stringWithFormat:@"%c", [string characterAtIndex:i]];
        [characters addObject:ichar];
    }
    return [characters copy];
}

Note that it is probably a lot easier to use recursion. Unfortunately, I am not on my mac at the moment, so I can't test it:

- (NSString *) randomStringWithLength:(int) len andAlphabet: (NSString *) alphabet {
    if(len <= 0 || ![alphabet count]){ // base case
         return @"";
    }
    int index = rand() % [alphabet count];
    NSString *chosenLetter = [alphabet substringWithRange:NSMakeRange(index, 1)];
    NSString *newAlphabet = [alphabet stringByReplacingCharactersInRange:NSMakeRange(index, 1) withString:@""];
    NSString *resultString = [NSString stringWithFormat:@"%@%@",chosenLetter,[self randomStringWithLength:len-1,newAlphabet];
    return resultString;
}
Josh Gafni
  • 2,831
  • 2
  • 19
  • 32
  • Thank you for your very fast answer. i think it is very simply but i don´t know how could i store the alphabet in an NSMutableArray? Could you please help me please? ;-) – euleec7 Feb 23 '15 at 22:56
  • NSString *alphabet = @"x"; [self.array addObject:alphabet]; – Earl Grey Feb 23 '15 at 23:14
  • Actually I would add the objects when you create the array: `NSMutableArray *array= [NSMutableArray arrayWithObjects:@"A", @"B", @"C", nil];` – Josh Gafni Feb 23 '15 at 23:30
  • Many Thanks. I think for my current knowledge in xcode, which is still too big for me. Unfortunately I do not know what I have to replace or delete code and where the new code has to be inserted. I need to practice, practice to improve. :-) – euleec7 Feb 23 '15 at 23:46
  • 2
    It may be better to use arc4random_uniform(N) as explained here: http://nshipster.com/random/ – Murray Sagal Feb 24 '15 at 01:11
  • error: use of undeclared identifier 'stranglength' in this part of code: __- (NSArray *) arrayFromString: (NSString *) string{ NSMutableArray *characters = [[NSMutableArray alloc] initWithCapacity:[stringlength]]; for (int i=0; i < [stringlength]; i++) { NSString *ichar = [NSString stringWithFormat:@"%c", [string characterAtIndex:i]]; [characters addObject:ichar]; } return [characters copy]; }__ – euleec7 Feb 24 '15 at 08:39
  • Sorry there should be a space between string and length. I'll edit my code tomorrow – Josh Gafni Feb 24 '15 at 08:44
  • with my IBAction is everything fine: - [self randomStringWithLength:1 andAlphabet:(NSString *)letters]; - but the letter repeats before all letters from A-Z are called. – euleec7 Feb 24 '15 at 12:02
  • which method did you use? the one with recursion? – Josh Gafni Feb 24 '15 at 18:08
  • i used the first one. – euleec7 Feb 24 '15 at 18:25
  • did you include the removeObjectAtIndex line of code? – Josh Gafni Feb 24 '15 at 18:27
0

because c string is terminal by '\0', we need 27 bytes.

    NSString *alp = @"ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    char cstr[27];

    [alp getCString:cstr maxLength:27 encoding:NSUTF8StringEncoding];

    // do i from 25 to 0. to 1 is ok, also
    for (int i = alp.length - 1; i >= 0; --i) {
        int mark = arc4random_uniform(i);
        char temp = cstr[i];
        cstr[i] = cstr[mark];
        cstr[mark] = temp;
    }

    NSString *str = [NSString stringWithUTF8String:cstr];

    NSLog(@"%@", str);
Mornirch
  • 1,144
  • 9
  • 10
  • Many Thanks. I think for my current knowledge in xcode, which is still too big for me. Unfortunately I do not know what I have to replace or delete code and where the new code has to be inserted. I need to practice, practice to improve. :-) – euleec7 Feb 23 '15 at 23:47
0

Lots of different ways to do this. My suggestion would be to use a mutable array:

Add this statement to your .h file:

NSMutableArray *randomLetters;

And then add this method to your .m file:

(Code edited to clean up a ton of typos and minor mistakes)

- (NSString *) randomLetter;
{
  if (randomLetters == nil)
    randomLetters = [NSMutableArray arrayWithCapacity: 26];
  if (randomLetters.count == 0)
  {
    for (unichar aChar = 'A';  aChar <= 'Z'; aChar++)
    {
      [randomLetters addObject: [NSString stringWithCharacters: &aChar length: 1]];
    }
  }
  NSUInteger randomIndex = arc4random_uniform((u_int32_t)randomLetters.count);
  NSString *result =  randomLetters[randomIndex];
  [randomLetters removeObjectAtIndex: randomIndex];
  return result;
}

(Disclaimer: I typed that code out in the SO editor. I haven't tried to compile it, so it may contain minor typos.)

The method randomLetter will give you a single, non-repeating random letter every time you call it, until the array of remaining random letters is empty. At that point it will repopulate the array with the full alphabet and start over.

The random number generator arc4random_uniform() gives much better results that rand(), and doesn't suffer from "modulo bias" (link) like the expression rand()%range does.

Note that it is possible for the above method to give you the last random letter (an "a", for example") then on the next call, repopulate the array, and give you another "a" from the newly populated array. However, the odds of that happening are only 1 in 26.

You could tweak the above code so it remembers the last character it gives you and doesn't give you that same character twice in a row if that's important.

You could pretty easily change it slightly so that it would give you letters one at a time until it's empty and then return nil, and then write a separate method to fill it. That way you could get exactly 26 non-repeating characters and know when you about to repeat with another set of 26 characters.

Community
  • 1
  • 1
Duncan C
  • 128,072
  • 22
  • 173
  • 272
  • @euleec7, I see in the history you attempted to edit my post to show a log of the syntax errors I said it likely contained. First, I said it was not compiled or tested, so it was likely to contain errors. My post was intended as a guide, not as drop in code that you could use without any effort. Second, don't edit somebody's post to reply to it. Post a comment. I have done some cleanup to my code. It may compile now. – Duncan C Feb 24 '15 at 17:46
  • Thank you! i will try it. and excuse me when i can´t understand something the first time. my english is not so good. :-) – euleec7 Feb 24 '15 at 18:14
  • it work´s fine!! no repeating! Thank you very much Duncan C.! – euleec7 Feb 24 '15 at 18:50
  • Glad I could help. If you think this answer is the best, please accept it. Upvotes are also appreciated, but that's up to you. – Duncan C Feb 24 '15 at 19:30
0

Given these methods:

- (NSString *)stringOfRandomLettersWithLength:(NSUInteger)length {

    if (length > 26) {
        return nil;
    }

    NSMutableString *stringOfRandomLetters = [NSMutableString stringWithCapacity:length];
    NSArray *letters = @[ @"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" ];
    NSMutableArray *unusedLetters = [letters mutableCopy];
    NSString *randomLetter;

    for (int i=0; i<length; i++) {
        randomLetter = [self randomItemFromArray:unusedLetters];
        [unusedLetters removeObject:randomLetter];
        [stringOfRandomLetters appendString:randomLetter];
    }

    return stringOfRandomLetters;
}

- (NSString *)randomItemFromArray:(NSArray *)items {

    if (items.count < 1) {
        return nil;
    }

    return items[ arc4random_uniform((u_int32_t)items.count) ];
}

You could create a string of random, distinct letters like this:

NSString *label = [self stringOfRandomLettersWithLength:26];
NSLog(@"label= %@", label);

In the console you'd see something like this:

label= YGRHCXTFDZLKNPAIEOJSUQWVMB
Murray Sagal
  • 8,454
  • 4
  • 47
  • 48
  • i think the error Property letters not found on object of type ViewController ist fixed with adding: @property (nonatomic, strong) NSMutableArray *letters; to my .m file. How could i display 1 character in my label witch is named " buchstabeAusgabe "? – euleec7 Feb 24 '15 at 07:47
  • _thise error is shown when i push my button_*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString appendString:]: nil argument' *** First throw call stack: (0x1826aa59c 0x192df40e4 0x1826aa4dc 0x182654b94 0x100025b14 0x1000263c4 0x186e8d418 0x186e7652c 0x186e8cdb4 0x186e8ca40 0x186e85f94 0x186e5968c 0x1870f860c 0x186e57bf4 0x1826629ec 0x182661c90 0x18265fd40 0x18258d0a4 0x18b7275a4 0x186ebeaa4 0x100026664 0x193462a08) libc++abi.dylib: terminating with uncaught exception of type NSException – euleec7 Feb 24 '15 at 08:00
  • Sorry about that. Copy and paste error. I've corrected the example. It should work now. – Murray Sagal Feb 24 '15 at 11:53
  • If you think this is the best answer then please accept it. Up-votes are also appreciated, although that's up to you. – Duncan C Feb 24 '15 at 19:25