1

How you code arc4random() that does not repeat number twice?

For instance. I'm using switch and button. I don't want to generate reused the same arc4random number again. If I have arc4random that generation numbers 2,4,42,32,42... I don't want to 42 to appear again.

How do I avoid this?

  switch (arc4random() % 50 )
        {
            case 1:
                text.text = @"You are silly boy";
                break;
            case 2:
                text.text = @"Well, you very very silly"];
                break;
            case 3:
                text.text = @"stop being silly"];
                break;
            case 4:
                [text.text = @"silly... silly"];
                break;
            case 5:
                text.text = @"what you silly boy"];
                break;

           ...
            case 0:
                text.text = @"you silly"];
                break;
        }
tshepang
  • 12,111
  • 21
  • 91
  • 136
user971636
  • 35
  • 7
  • How often can they not repeat? – Paul.s Jan 07 '12 at 21:23
  • 1
    Fisher-Yates: see here: http://stackoverflow.com/questions/1858610/different-numbers-from-1-to-10/1858800#1858800 – paxdiablo Jan 07 '12 at 21:25
  • The result from arc4random likely doesn't repeat for about 2 billion numbers. But, since the numbers are (pseudo) random, when you use %50 you could get two identical numbers in a row. You must use some other strategy to assure uniqueness. – Hot Licks Jan 07 '12 at 21:32

2 Answers2

6

arc4random() is not a repeating generator, that is each invocation is independent of all other invocation. But that also means that just invoking arc4random() will not (generally) produce 50 unique numbers.

One way is to create an array of the integers you want and then walk through the array and swap each one with another chosen at random (in your case) with (arc4random() % 50). They just use consecutive values from the array and when at the end create a new array and randomize it.

Example: The values in the list will be random numbers between 0 and 49 with no repeats:

int n = 50;
int list[n];
for (int i = 0; i<n; i++)
    list[i] = i;

for (int i = n-1; i>=1; i--) {
    int ran = arc4random() % (i+1);
    int tmp = list[i];
    list[i] = list[ran];
    list[ran] = tmp;
}

for (int i = 0; i<n; i++)
    NSLog(@"%d", list[i]);

This is the modern version of the Fisher–Yates shuffle, designed for computer use and introduced by Richard Durstenfeld.

Note: using mod to create a subset creates a bias but in a case of 50 the bias is negligible.

zaph
  • 111,848
  • 21
  • 189
  • 228
  • 1
    I doubt about this method's randomness distribution. Have a look at http://stackoverflow.com/questions/859253/why-does-this-simple-shuffle-algorithm-produce-biased-results-what-is-a-simple – tia Jan 08 '12 at 14:09
  • I have updated the example to the Fisher–Yates algorithm as updated by Durstenfeld. – zaph Jan 08 '12 at 14:56
-1

One way of doing it would be as follows:

static int maxNumOfCases = 50; //This could be any number of cases that you need in your app.

......

switch (arc4random() % (maxNumOfCases--)) {
            case 1:
                text.text = @"You are silly boy";
                break;
            case 2:
                text.text = @"Well, you very very silly"];
                break;
            case 3:
                text.text = @"stop being silly"];
                break;
            case 4:
                [text.text = @"silly... silly"];
                break;
            case 5:
                text.text = @"what you silly boy"];
                break;
                ...
            case 0:
            text.text = @"you silly"];
            break;
}

This code always switches to a unique case on each invocation. The way the code works is by decreasing the range of arc4random() at each invocation by 1.

Update: Keep note that this method biases more towards the end of the run to a smaller range of numbers. So this is not a true non-repeating random number generation. But if thats not a concern, its an easy one liner to include in your code.

Krishna K
  • 708
  • 3
  • 10
  • 1
    There is a very substantial bias with this method. For `r = (arc4random() % (maxNumOfCases--))` where `maxNumOfCases` is initially 50, as `maxNumOfCases` approaches 0, r approaches 0. For `maxNumOfCases` of 50, r=1 will occur 7.0% of the time and r=50 will occur 0.08% of the time with the other values ramping between these values. For this case **r=1 is over 80 times more likely than r=50.** (The percentage values are approximate but close, these values were calculated empirically over 500,000,000 tries). – CocoaFu 11 mins ago – zaph Jan 08 '12 at 13:30
  • Wait a second- this isn't even functional. It can still repeat numbers. How was this accepted. – IAmTheAg Oct 14 '14 at 21:18