1

我在 Xcode 中使用 arc4random 生成随机值时遇到问题。我想从随机生成中排除那些已经被拾取的数字。这是我写的算法

int randomValue =  (arc4random() % numberofquest)+ 1;
int kk=1;

if (kk==1) {

//first time add the first random value
[oldquest addObject: randomValue];
    }
else {
        //control if the number is already in the vector
        for (int j=1; j<[oldquest count]; j++)
        {

            if (randomValue==oldquest[j])
            {

                randomValue =  (arc4random() % numerodomande)+ 1;
            }
            else
            {
                [oldquest addObject: randomValue];
            }
        }

}
kk=kk+1

但它不起作用。我想可能是因为 randomvalue 和数组中的第 j 个对象不可比较(第一个整数和第二个字符串?)。任何人都可以帮助我吗?

4

3 回答 3

2

对不起,阿瑞斯的回答几乎是正确的。您可以比较两个不同的 NSNumber 对象。

这是我的解决方案:

- (int) generateRandomNumber {
    int number = arc4random() % 100;

    if ([chosen_numbers indexOfObject:[NSNumber numberWithInt:number]]!=NSNotFound)
        number = [self generateRandomNumber];

    [chosen_numbers addObject:[NSNumber numberWithInt:number]];
    return number;
}

由于 Alessandro 在实现它时遇到了一些麻烦,因此在 UIViewController 类中提供了一个示例。这适用于 100 个数字:

#import "ViewController.h"

@implementation ViewController {
    NSMutableArray * chosen_numbers;    
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    chosen_numbers = [[NSMutableArray alloc] init];

    for(int i = 0; i<90; i++) {
        NSLog(@"number: %d",[self generateRandomNumber]);
    }
}

- (int) generateRandomNumber {
    int number = arc4random() % 100;

    if ([chosen_numbers indexOfObject:[NSNumber numberWithInt:number]]!=NSNotFound)
        number = [self generateRandomNumber];

    [chosen_numbers addObject:[NSNumber numberWithInt:number]];
    return number;
}

@end
于 2013-02-22T18:58:35.283 回答
1

这个怎么样:

    -(void) generateRandomNumber {

        int randomValue =  arc4random_uniform(numberofquest) + 1;

        if([oldQuest indexOfObject:[NSNumber numberWithInt:randomValue] == NSNotFound) {
            //Unique value
            [oldQuest addObject:[NSNumber numberWithInt:randomValue]];
        }
        else {
            //Value already exists. Look for another one
            return [self generateRandomNumber];

        }
    }

显然 oldQuest 是之前初始化的 NSMutableArray 实例。

于 2013-02-22T18:49:55.490 回答
1

你是对的 - 它不起作用,因为这里:

            if (randomValue==oldquest[j])

您正在尝试将 aint与对象进行比较... NSArrays 只能存储对象。事实上,这条线不应该因为这个原因而工作:

[oldquest addObject: randomValue];

您需要将 int 装箱为 NSNumber 并将其存储在数组中:

NSNumber* boxedRandomValue = [NSNumber numberWithInt:randomValue];
[oldquest addObject: boxedRandomValue];

-(int)intValue然后在比较值之前使用 NSNumber 实例方法将其拆箱:

 if (randomValue==[oldquest[j] intValue])

更新

您还必须注意其他一些问题:

  • kk 的值在每次测试迭代中重置为 1,因此kk == 1始终为真,else从不调用该子句。您只需在此代码块之外设置一次(例如,您可以将其设为属性,在初始化时将其设置为 1,然后在此处访问并递增它)。更好的是,只需使用 [oldquest count] 代替:if ([oldquest count]==0) {} else {}. 然后你就可以完全不用你的kk柜台了。

  • 您的 for 循环以 j=1 开头。这应该是 j=0 来寻址数组中的第一项(项 0)。

更新 2

这一行:randomValue = (arc4random() % numerodomande)+ 1由于它在检查循环中的位置,将导致各种其他问题。尝试以下建议之一:

  • return在你遇到骗子的时候。没有数字被添加到数组中......

  • 在循环内设置一个 BOOL 测试,在外面处理它:

    BOOL repeatedValue = NO;
    for (int j=0; j<[self.oldquest count]; j++){
        if (randomValue==[self.oldquest[j] intValue]) {
            repeatedValue = YES;
            break;
        }
    }
    if (repeatedValue){
        NSLog (@"value repeated");
        [self addRandom];  
        //recursive call to this code block, 
        //assuming it is a method called `addRandom`
    }
    
  • 尝试最后一个建议的紧凑版本(类似于 Odrakir 的解决方案) - 我已将其包含在一个addRandom方法中,以便您可以了解如何递归调用它。

      - (void) addRandom {
        int numberofquest = 5;
        int randomValue =  (arc4random() % numberofquest)+ 1;
        NSNumber* boxedValue = [NSNumber numberWithInt:randomValue];
        if ([self.oldquest indexOfObject:boxedValue]==NSNotFound) {
            [self.oldquest addObject: boxedValue];
        } else {
            [self addRandom];
        }
    }
    

    (如果你一直循环直到你找到一个唯一的数字,你将不得不小心,因为你的总数字集是有限的numberofquest,所以当你有一个完整的数字集时,你最终可能会陷入无限循环。)

  • 您可以使用 MutableOrderedSet 而不是使用 NSMutableArray,而是使用 MutableOrderedSet - 它是唯一对象的有序集合,因此不会两次添加对象。

在@interface

@property (nonatomic, strong) NSMutableOrderedSet setOfRandoms;

在@实现中

int randomValue =  (arc4random() % numberofquest)+ 1;
NSNumber randomValueBoxed = [NSNumber numberWithInt:randomValue];
[setOfRandoms addObject:randomValueBoxed];

更新 3

前面的提示假定它是您感兴趣的随机数列表。这是一个完整的解决方案,用于在自包含方法中返回一个新的唯一随机 int。

您需要在 @interface 中设置 2 个属性并在某处初始化它们

@property (nonatomic, assign) int maxRand;
    //stores the highest allowed random number

@property (nonatomic, strong) NSMutableArray* oldRands;
    //stores the previously generated numbers

uniqueRandom每次返回一个介于 1 和 self.maxRand 之间的唯一随机数。如果已返回所有允许的数字,则返回 0。

- (int) uniqueRandom {
    int result = 0;
    if ([self.oldRands count] != self.maxRand) {
        int randomValue =  (arc4random() %  self.maxRand )+ 1;
        NSNumber* boxedValue = [NSNumber numberWithInt:randomValue];
        if ([self.oldRands indexOfObject:boxedValue]==NSNotFound) {
            [self.oldRands addObject: boxedValue];
            result = randomValue;
        } else {
             result = [self uniqueRandom];
        }
    }
    return result;
}

您应该考虑到一旦初始化 self.maxRand 就更改它是没有意义的,除非您还重置 self.oldRands。因此,您可能想使用constor#define代替,和/或将其绑定到您的self.oldRands初始化程序。

于 2013-02-22T19:04:21.163 回答