配列をランダムかき混ぜる
PerlFAQ(CPAN以下の/doc/FAQs/FAQ/PerlFAQ.htmlにあります。)
より抜粋。
---------------- FAQ ここから ---------------------
[How do I shuffle an array randomly?]
> [配列をランダムに混ぜるには?]
Here's a shuffling algorithm which works its way through
the list, randomly picking another element to swap the
current element with:
> 以下が、質問と同じ動作をするアルゴリズムです。
> 新しい配列に追加するためにランダムに要素を拾っています。
srand;
@new = ();
@old = 1 .. 10; # just a demo
while (@old) {
push(@new, splice(@old, rand @old, 1));
}
For large arrays, this avoids a lot of the reshuffling:
> 大きな配列の場合。大量の並替えを防ぎます。
srand;
@new = ();
@old = 1 .. 10000; # just a demo
for( @old ){
my $r = rand @new+1;
push(@new,$new[$r]);
$new[$r] = $_;
}
> 灰色部かなだ訳。かなり意訳。
---------------- FAQ ここまで ---------------------
配列がでかい場合には、2番目の方法が効率が良いでしょう。
spliceを使わないし、元の配列を壊しません。
またファイルから読んで、行ごとにランダムに混ぜたい場合
はfor(@old)の代わりにwhile(<FILE>)とし、
srand;
@new = ();
open(FILE, "混ぜたいファイル");
for(<FILE>){
my $r = rand @new+1;
push(@new,$new[$r]);
$new[$r] = $_;
}
close(FILE);
のようにやれば配列・メモリの無駄遣いをせずに済みます。
#以下余談
配列からランダムに1つ取り出したい場合は単に
srand;
print $foo[rand @foo];
の様にすれば良いでしょう。
ファイルから、ランダムに1行「だけ」取り出したい場合は、
同FAQの「How do I select a random line from a file?」
や赤ラクダ本の316pの例にあるように
srand;
open(FILE, "filename");
rand($.) < 1 && ($it = $_) while <FILE>;
close(FILE);
print $it;
としてやれば良いと思います。