iOS:如何生成8个独特的随机整数?

10

我需要生成8个随机整数,但它们需要是唯一的,即不重复。

例如,我想要在1到8的范围内生成8个数字。

我看过arc4random,但不确定如何使它们唯一?

解决方法

-(NSMutableArray *)getRandomInts:(int)amount from:(int)fromInt to:(int)toInt {

  if ((toInt - fromInt) +1 < amount) {
      return nil;    
  }

  NSMutableArray *uniqueNumbers = [[[NSMutableArray alloc] init] autorelease];
  int r;
  while ([uniqueNumbers count] < amount) {

      r = (arc4random() % toInt) + fromInt;
      if (![uniqueNumbers containsObject:[NSNumber numberWithInt:r]]) {
          [uniqueNumbers addObject:[NSNumber numberWithInt:r]];
      }
  }
  return uniqueNumbers;
}

3
似乎问题需要进行更正:在1到8的范围内,只有8个独特整数可供选择... 只提供了1种选择。 - Vladimir
1
@Vladimir:看起来暗示的是在这种情况下顺序是随机的。 - Mike DeSimone
啊,应该是 toInt - fromInt :) 完成了。 - Jules
你的解决方案代码在执行1到10时给出正确答案,但在执行51到60时却给出了以下结果: 54、72、53、102、60、87、52、84、75、109。 - raw3d
6个回答

14
-(NSMutableArray *)getEightRandom {
  NSMutableArray *uniqueNumbers = [[[NSMutableArray alloc] init] autorelease];
  int r;
  while ([uniqueNumbers count] < 8) {
    r = arc4random();
    if (![uniqueNumbers containsObject:[NSNumber numberWithInt:r]]) {
      [uniqueNumbers addObject:[NSNumber numberWithInt:r]];
    }
  }
  return uniqueNumbers;
}

如果你想将数值限制在某个阈值M以下,那么你可以这样做:

-(NSMutableArray *)getEightRandomLessThan:(int)M {
  NSMutableArray *uniqueNumbers = [[[NSMutableArray alloc] init] autorelease];
  int r;
  while ([uniqueNumbers count] < 8) {
    r = arc4random() % M; // ADD 1 TO GET NUMBERS BETWEEN 1 AND M RATHER THAN 0 and M-1
    if (![uniqueNumbers containsObject:[NSNumber numberWithInt:r]]) {
      [uniqueNumbers addObject:[NSNumber numberWithInt:r]];
    }
  }
  return uniqueNumbers;
}

如果M=8,或者M接近8(例如9或10),那么这将需要一些时间,你可以更聪明地解决它。

-(NSMutableArray *)getEightRandomLessThan:(int)M {
  NSMutableArray *listOfNumbers = [[NSMutableArray alloc] init];
  for (int i=0 ; i<M ; ++i) {
    [listOfNumbers addObject:[NSNumber numberWithInt:i]]; // ADD 1 TO GET NUMBERS BETWEEN 1 AND M RATHER THAN 0 and M-1
  }
  NSMutableArray *uniqueNumbers = [[[NSMutableArray alloc] init] autorelease];
  int r;
  while ([uniqueNumbers count] < 8) {
    r = arc4random() % [listOfNumbers count];
    if (![uniqueNumbers containsObject:[listOfNumbers objectAtIndex:r]]) {
      [uniqueNumbers addObject:[listOfNumbers objectAtIndex:r]];
    }
  }
  [listOfNumbers release];
  return uniqueNumbers;
}

#include <stdlib.h>。另外,PengOne有一个打字错误:应该是 arc4random 而不是 acr4random - Art Gillespie
2
-1. 尽管这个答案对于小数字可能没有明显的副作用,但它教授了一个不好的解决方案,这实际上是一个洗牌问题。这个算法永远不能保证完成。请参见@Art Gillespie的答案以获取适当的代码片段。(我在这里投反对票,作为潜在未来读者的指示标志,因为这个答案被接受了。) - Ben Zotto
@quixoto:有一定的概率,它将在有限的时间内终止。此外,第三个建议给出了一个在8步内终止的排列生成算法。而且,他并不一定需要连续的8个数字。 - PengOne
@quixoto:你的评论比对一个正确答案进行负评更能够为潜在的读者提供更好的信息,这只是提醒。 - PengOne
哇,整整一年都没有人注意到这个问题? - occulus
显示剩余2条评论

9

独一无二的特性是你需要提供的——随机API不会为你做到这一点。

正如已经建议的那样,你可以生成一个数字,然后检查它是否与你已经生成的某些东西相冲突,如果是,就再试一次。但请注意,这取决于数字的数量和范围的大小,这将成为一个没有保证终点的算法。

如果你真的只是想得到一个随机顺序的连续数字集合,这不是做到这一点的方法,因为它可能需要不可预测的长时间才能完成。在这种情况下,首先构建一个包含所有所需值的数组,然后“洗牌”该数组是更好的选择。最好的洗牌方法是Fisher-Yates,但如果你不需要它完全公正,你也可以做描述这里的事情。


我有50个问题,需要随机出现。我该怎么做? - Vineesh TP

7

检查已生成的数字可能是非常耗时的(理论上来说,这可能需要永远的时间)。但是,这是一个已经解决的问题。您需要一个洗牌算法,例如Fisher-Yates_shuffle

在iOS上可能是这样的:

NSMutableArray *randSequence = [[NSMutableArray alloc] initWithCapacity:8];
for (int ii = 1; ii < 9; ++ii)
    [randSequence addObject:[NSNumber numberWithInt:ii]];

for (int ii = 8; ii > 0; --ii) {
    int r = arc4random() % (ii + 1);
    [randSequence exchangeObjectAtIndex:ii withObjectAtIndex:r];

// you can now iterate over the numbers in `randSequence` to get
// your sequence in random order

1
如果ii从8开始递增,那么它将始终大于0,因此这肯定永远不会终止。 - PengOne
这有点晚了,但是你不必考虑偏差吗?难道你不应该将 int r = arc4random() % 8 更改为 int r = arc4random() % i 吗? - Byte
@Byte 你说得完全正确,甚至更好的方法是 int r = arc4random_uniform(i)+1; - Kaan Dedeoglu

2

将数字存储在数组中,每次生成下一个数字时,检查它是否已经存在于数组中。如果不存在,则将其添加并继续。


1

这里是一些伪代码

  1. 对于1-8中的每个数字,生成一个随机数。
  2. 将随机数和整数作为键值对添加到字典中。
  3. 将字典的所有键作为数组获取(提示:查看allKeys方法)。
  4. 对该数组进行排序(升序或降序都可以)。
  5. 现在,对于这些数字中的每一个作为键,从字典中获取相应的整数。

它能工作,但是洗牌更好,因为效率更高,尽管使用仅有的八个整数应该并不重要。 - vakio
我只是想提供另一种重新排序列表的方法,而不必编写任何代码。至于效率——如果没有进行分析或分析其他算法,我无法告诉您。 - Abizern

0

尝试这段代码...它将为您提供可变数组中所有可能的唯一数字集合...

-(NSInteger) randomNumber {
NSInteger newRandomNumber = (NSInteger) arc4random() % 10;
NSInteger uniqueNumber;
if ([self.arrayContainingNumbers containsObject: [NSNumber numberWithInteger:newRandomNumber]]) {
    [self randomNumber];
    } else {
    [self.arrayContainingNumbers addObject: [NSNumber numberWithInteger:newRandomNumber]];
}
uniqueNumber = [[self.mutableArrayContainingNumbers lastObject]integerValue];
     NSLog(@"new Unique Number is %ld",(long)uniqueNumber);

return uniqueNumber;  
}

不要忘记添加这个方法 :)
    -(NSMutableArray *) arrayContainingNumbers {
if (!_mutableArrayContainingNumbers) {
    _mutableArrayContainingNumbers = [[NSMutableArray alloc] init];
}
return _mutableArrayContainingNumbers; 
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接