Objective-C如何从NSArray中抽取几个随机项目而不重复?

我有一个随机属性的数组,我想在我正在开发的游戏中分配给设备。

我在下面使用的代码是返回一个NSArray。 我感兴趣的是,如果有方法从该数组中获取项目索引而不会获得重复的值。 显而易见的解决scheme是用返回的数组创build一个可变数组,随机,删除返回的项目,并循环,直到收到项目的数量。

有没有不同的方式从NSArray中获取X个随机项目而不重复?

//get possible enchantments NSPredicate *p = [NSPredicate predicateWithFormat:@"type = %i AND grade >= %i", kEnchantmentArmor,armor.grade]; NSArray* possibleEnchantments = [[EquipmentGenerator allEnchantmentDictionary] objectForKey:@"enchantments"]; //get only applicable enchantments NSArray *validEnchantments = [possibleEnchantments filteredArrayUsingPredicate:p]; NSMutableArray* mutableArray = [NSMutableArray arrayWithArray:validEnchantments]; NSDictionary* enchantment = nil; if(mutableArray.count>0) { //got enchantments, assign number and intensity based on grade for (int i = 0; i<3;i++) { enchantment = mutableArray[arc4random()%mutableArray.count]; [mutableArray removeObject:enchantment]; //create enchantment from dictionary and assign to item. } } 

您可以使用以下技术之一对数组进行洗牌:

什么是最好的方式来洗牌NSMutableArray?
不重复的随机数字

然后,从数组中获取第一个X元素。

很多年前,我在做纸牌游戏,我意识到洗牌是一个无效的方式来获得随机卡。 我会在你的鞋子中做的是随机select一个元素,然后用数组末尾的元素replace它,如下所示:

 @interface NSMutableArray (pickAndShrink) - (id) pullElementFromIndex:(int) index // pass in your random value here { id pickedItem = [self elementAtIndex:index]; [self replaceObjectAtIndex:index withObject:[self lastObject]]; [self removeLastObject]; return pickedItem; } @end 

每次你用这种方式拉一个元素时,数组会缩小一个。

你可以使用一个随机数发生器来select一个起始索引,然后根据某种math函数select后续的索引。 你仍然需要循环取决于你想要多less个属性。

例如:

 -(NSMutableArray*)getRandomPropertiesFromArray:(NSArray*)myArray { int lengthOfMyArray = myArray.count; int startingIndex = arc4random()%lengthOfMyArray; NSMutableArray *finalArray = [[NSMutableArray alloc]init]autorelease]; for(int i=0; i<numberOfPropertiesRequired; i++) { int index = [self computeIndex:i usingStartingIndex:startingIndex origninalArray:myArray]; [finalArray addObject:[myArray objectAtIndex:index]]; } return finalArray; } -(int)computeIndex:(int)index usingStartingIndex:(int)startingIndex { //You write your custom function here. This is just an example. //You will have to write some code to make use you don't pick an Index greater than the length of your array. int computedIndex = startingIndex + index*2; return startingIndex; } 

编辑:即使你的computeIndex函数可以使用随机挑选后续指标。 既然你有一个startingIndex和另一个索引,你可以用它来抵消你的函数,这样你就不会select重复的东西了。

编辑︰如果你的数组是非常大的,你需要select的子集是小的,而不是洗牌整个数组(也许更昂贵),你可以使用这种方法来select你需要的项目数。 但是,如果你的数组很小,或者你需要select的项目数量几乎是数组的大小,那么godel9的解决scheme会更好。

你可以使用一个可变数组,然后在选中时删除它们,使用类似random()%array.count的方法来得到一个随机索引。 如果你不想修改数组然后复制它[数组mutableCopy]。