【Xcode5.1.1 + iOS 7.1 + MacOX10.9.5】
配列からランダムな数を取得するというのは、どんなプログラムでもよくやります。
for (int i=[iconArray count]-1; i>=0; i--) { int j = rand() % (i+1); [iconArray exchangeObjectAtIndex:i withObjectAtIndex:j]; }
一見よさそうだけど、なんとコレ、毎回同じ数値しか返ってきません。このrand()という関数は、毎回初期化しないと同じ値を返すらしい。たとえばこの記事なんかは、初期化をすっ飛ばして書いてあるので、実際に使ってみるとハマるわけです(笑)。
※上の処理だと、初期化がまったく行われていないので、ビルドしたアプリを起動し直しても、ビルドし直しても毎回必ず同じ値になります。
で、初期化を加えたのがコレ。
srand(time(NULL)); for (int i=[iconArray count]-1; i>=0; i--) { int j = rand() % (i+1); [iconArray exchangeObjectAtIndex:i withObjectAtIndex:j]; }
srand()はrand()の初期化用関数で、毎回違う値を返すことで、返す値が変わることになるらしい。
【参考】
・指定した範囲内で乱数を発生させる | Objective-Cでのアプリ開発記
で、こっちのarc4random()は初期化込みの関数で、初期化を意識せずに使える。
for (int i=[iconArray count]-1; i>=0; i--) { int j = arc4random() % (i+1); [iconArray exchangeObjectAtIndex:i withObjectAtIndex:j]; }
この方法が、初期化ミスもなく一番いいのではないかという結論になるわけですが。
【参考】
・[Xcode]ランダム数値の生成 | C++ | alperithm
・iPhone-Labo: ランダムな数値を取得する – rand() arc4random()
ググってみるとだいたい「arc4random()使えば問題ないよね」って書いてあるんだけど、そもそもsrand()とrand()が別々に実装されている理由って何なんですかね?そっちの方がすごく気になる。知ってる人がいたら教えてください。
ちなみにココで書かれている、配列を後ろから参照して入れ替える方法をFisher–Yatesアルゴリズムというらしい。初めて聞きました。
【参考】
・Fisher–Yatesアルゴリズムがすごかったです。: PandaNoir
・Fisher-Yates Shuffle – Faith and Brave – C++で遊ぼう