Perlでスマートに配列からランダムで特定個数の値を取得する

TL;DR

use List::Util qw(sample);

my @array = (1..100);
# 3個ランダムでとりだす

my @random_pickup = sample 3, @array;

人間生きていると配列の中身からランダムにn個取得したいときがあります。Perl書いているときもありますね。

よくある方法は次のような感じでしょうか

my @array = (1..100);
my @random_array =  shuffle @array ;
my @random_pickup  = splice @random_array, 0, 3;

List::Utilのshuffleを使い配列をランダムにばらしたあとに、標準関数のspliceを使い特定の数の値を取り出してきます。 これだと@random_pickupには3つのランダムな数が入る訳ですね。

ただしこの方法だと必ず全件をshuffleしないといけないため、巨大な配列を対象にする場合はそこそこコストが掛かります。 他には結局@random_pickupが必要な場合は、中間変数の@random_arrayが不必要ですね。 (最も、工夫すれば中間変数を作らずにかけますが...)

そこでオススメなのがList::Utilのsample関数です。1.54から同梱されているので、比較的最近のList::Utilになら入っています。 ちなみにList::MoreUtilsにも入っています。

書き方は簡単で以下の感じです。

my @items = sample $count, @values; # sample {取得したい数}、 {リスト}

$count@valuesの配列長より大きい場合は、shuffleと同じ挙動になります。

近年のList::UtilはXS(C言語実装)も同梱されており、sampleも見てみるとC言語レベルで特定個数のランダム取得をしてくれています。 このため、コスト的にもshuffleしてからspliceなどで取得するより最適化されておりオススメです。 metacpan.org