2010-07-23 61 views
80

說我有一個包含對象的數組,1,2,3和4. 如何從這個數組中選取一個隨機對象?在NSArray中選取一個隨機對象

+0

這裏的所有答案都是正確的,但對於更新的解決方案,請參閱我的答案[here](http://stackoverflow.com/a/10837462/730701)。它使用'arc4random_uniform'方法來避免模偏差。 – Adam 2013-05-28 21:57:58

回答

184

@達里爾的答案是正確的,但可以使用一些小的調整:

NSUInteger randomIndex = arc4random() % [theArray count]; 

修改:

  • 使用arc4random()超過rand()random()是簡單,因爲它不需要播種(呼叫srand()srandom())。
  • modulo operator%)使總體語句更短,同時也使語義更清晰。
  • theArray.count是錯誤的。它將起作用,但count未在NSArray上聲明爲@property,因此應通過點語法調用而不是。它的作用只是編譯器如何解釋點語法的副作用。
+2

請注意,RC4/ARC4不提供統一的輸出。 – 2010-07-23 15:01:20

+43

「theArray.count是錯誤的,它可以工作,但count並沒有在NSArray上聲明爲@property,因此不應該通過點語法來調用。」 ---這是不正確的。點語法和聲明的屬性實際上並沒有關聯:你可以在沒有參數的方法上使用點語法而根本沒有問題。 – 2012-02-14 17:00:06

+27

從arc4random手冊頁:arc4random_uniform()被推薦用於類似'arc4random()%upper_bound''的結構,因爲當上限不是2的冪時,它避免了「模偏置」。 – 2012-06-15 01:12:36

1

生成一個隨機數並將其用作索引。例如:

#import <Foundation/Foundation.h> 

int main(int argc, const char * argv[]) 
{ 
    @autoreleasepool { 
     NSArray *array = [NSArray arrayWithObjects: @"one", @"two", @"three", @"four", nil]; 
     NSUInteger randomNumber; 
     int fd = open("/dev/random", O_RDONLY); 
     if (fd != -1) { 
      read(fd, &randomNumber, sizeof(randomNumber)); 
      close(fd); 
     } else { 
      fprintf(stderr, "Unable to open /dev/random: %s\n", strerror(errno)); 
      return -1; 
     } 
     double scaledRandomNumber = ((double)randomNumber)/NSUIntegerMax * [array count]; 
     NSUInteger randomIndex = (NSUInteger)floor(scaledRandomNumber); 
     NSLog(@"random element: %@", [array objectAtIndex: randomIndex]); 
    } 
    return 0; 
} 
+0

這麼簡單,但它工作得很好! – Joshua 2010-07-23 14:20:09

+0

@Joshua如果你想要更多的細節,你可以使用'SecRandomCopyBytes()'在iPhone上獲取加密有用的隨機數。在Mac上,您可以直接訪問/ dev/random。 – 2010-07-23 14:31:32

+0

一個隨機數應該足夠了,但無論如何感謝增加的信息。 – Joshua 2010-07-23 14:37:50

10

也許東西沿着線:

NSUInteger randomIndex = (NSUInteger)floor(random()/RAND_MAX * [theArray count]); 

不要忘了初始化隨機數發生器(srandomdev(),例如)。

注意:根據以下答案,我已更新爲使用-count而不是點語法。

0
srand([[NSDate date] timeIntervalSince1970]); 

int inx =rand()%[array count]; 

inx是隨機數。

其中srand()可以在隨機選取函數之前的程序中的任何地方。

16

這是我能想出的最簡單的辦法:

id object = array.count == 0 ? nil : array[arc4random_uniform(array.count)]; 

因此,有必要檢查count因爲非nil但空NSArray將返回0count,並arc4random_uniform(0)回報0。所以沒有檢查,你會超出陣列的界限。

該解決方案是誘人的,但錯誤,因爲它會導致一個空數組崩潰:

id object = array[arc4random_uniform(array.count)]; 

僅供參考,這裏的documentation

u_int32_t 
arc4random_uniform(u_int32_t upper_bound); 

arc4random_uniform() will return a uniformly distributed random number less than upper_bound. 

手冊頁沒有按」當0作爲upper_bound傳遞時,請提及arc4random_uniform返回0

此外,arc4random_uniform<stdlib.h>中定義,但在我的iOS測試程序中添加#import不是必需的。

9
@interface NSArray<ObjectType> (Random) 
- (nullable ObjectType)randomObject; 
@end 

@implementation NSArray (Random) 

- (nullable id)randomObject 
{ 
    id randomObject = [self count] ? self[arc4random_uniform((u_int32_t)[self count])] : nil; 
    return randomObject; 
} 

@end 

編輯:更新了Xcode的7仿製藥,爲空

0
ObjectType *objectVarName = [array objectAtIndex:arc4random_uniform((int)(array.count - 1))]; 

如果要強制轉換成int類型,下面是當你需要從一個隨機的int作爲該解決方案(有用非順序編號的數組,在隨機化枚舉呼叫的情況下,等等)

int intVarName = (int)[(NSNumber *)[array objectAtIndex:arc4random_uniform((int)(array.count - 1))] integerValue]; 
0

在夫特4:

let array = ["one","two","three","four"] 
let randomNumber = arc4random_uniform(UInt32(array.count)) 

array[Int(randomNumber)] 
+0

請複習[我如何寫出一個好答案](https://stackoverflow.com/help/how-to-answer)。不接受代碼的答案是不鼓勵的,因爲他們沒有解釋他們如何解決問題中的問題。你應該更新你的答案,以解釋這是什麼以及它如何改善這個7歲的問題已經有的許多答案 – FluffyKitten 2017-10-12 21:28:21