How can I efficiently select several unique random numbers from 1 to 50, excluding x?

后端 未结 5 428
囚心锁ツ
囚心锁ツ 2021-01-06 19:01

I have 2 numbers which are between 0 and 49. Let\'s call them x and y. Now I want to get a couple of other numbers which are not x or y, but are al

相关标签:
5条回答
  • 2021-01-06 19:15

    You can use something called the Fisher-Yates shuffle. It's an efficient algorithm for producing a randomly ordered list of values from some set. You would first exclude N from the list of values from which to get random values, and then perform the shuffle.

    0 讨论(0)
  • 2021-01-06 19:15

    I'd do something more along the lines of:

    NSMutableSet * invalidNumbers = [NSMutableSet set];
    [invalidNumbers addObject:[NSNumber numberWithInt:x]];
    [invalidNumbers addObject:[NSNumber numberWithInt:y]];
    
    int nextRandom = -1;
    do {
      if (nextRandom >= 0) {
        [invalidNumbers addObject:[NSNumber numberWithInt:nextRandome]];
      }
      nextRandom = arc4random() % 49;
    } while ([invalidNumbers containsObject:[NSNumber numberWithInt:nextRandom]]);
    
    0 讨论(0)
  • 2021-01-06 19:16

    You should shuffle an array of numbers (of values [0, ..., 49] in your case; you can also exclude your x and y from that array if you already know their values), then grab the first N values (however many you're seeking) from the shuffled array. That way, all the numbers are randomly of that range, and not "seen before".

    0 讨论(0)
  • 2021-01-06 19:33

    First, make a set of valid numbers:

    // Create a set of all the possible numbers
    NSRange range = { 0, 50 };// Assuming you meant [0, 49], not [0, 49)
    NSMutableSet *numbers = [NSMutableSet set];
    for (NSUInteger i = range.location; i < range.length; i++) {
        NSNumber *number = [NSNumber numberWithInt:i];
        [numbers addObject:number];
    }
    
    // Remove the numbers you already have
    NSNumber *x = [NSNumber numberWithInt:(arc4random() % range.length)];
    NSNumber *y = [NSNumber numberWithInt:(arc4random() % range.length)];
    NSSet *invalidNumbers = [NSSet setWithObjects:x, y, nil];
    [numbers minusSet:invalidNumbers];
    

    Then, if you don't need the numbers to be guaranteed to be random, you could use -anyObject and -removeObject to pull out a couple of other numbers. If you do need them to be random, then follow LBushkin's answer, but be careful not to accidentally implement Sattolo's algorithm:

    // Shuffle the valid numbers
    NSArray *shuffledNumbers = [numbers allObjects];
    NSUInteger n = [shuffledNumbers count];
    while (n > 1) {
        NSUInteger j = arc4random() % n;
        n--;
        [shuffledNumbers exchangeObjectAtIndex:j withObjectAtIndex:n];
    }
    
    0 讨论(0)
  • 2021-01-06 19:36

    You could add x, y and the new number to a data structure that you can use as a set and do something like (in pseudo-code; the set structure needs something like push to add values and in for checking membership):

    number_of_randoms = 2;
    
    set.push(x);
    set.push(y);
    
    for (i = 0; i<number_of_randoms; i++) {
      do {
        new_random = arc4random() % 49;
      } while !set.in(new_random);
      set.push(new_random);
    }
    

    So if objc has something appropriate, this is easy...[aha, it does, see Dave DeLong's post].

    This algorithm makes sense if number_of_randoms is much less than 49; if they are comparable then you should one of the shuffle (aka permutation) ideas.

    0 讨论(0)
提交回复
热议问题