March 04, 2010
■ [perl][func][memo]配列をshuffle(ランダムに並べ替えたい)/take potluck(ランダムに抜き出したい)

たまーに配列を適当に並べ替えたり、そこからいくつか抜き出したいってことがあります。そんなときのためのTIP。
並べ替え
お手軽に
sub shuffle { return sort { int(rand 3) - 1 } @_ } print shuffle(0 .. 9); # 0123456789 => 6517840923
非常に簡単です。ただ元の配列の並びの影響を受けやすいので、内容が10~20個程度の配列なら気にならないですが、それ以上になるとあまり役に立ちません。
きちんと
sub shuffle { my @old = @_; local $_; my ($i, $new) = ($#old+1, 0); map { $_ = $old[$new = rand $i--]; $old[$new] = $old[$i]; $_; } 0 .. $#old } print shuffle(0..9,A..Z,a..z); # before: 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz # after : qBwNj3uiMgtLG9TKs6Ry7fpmZvVUSDQOdEeaJWoX8nlr5Cc0h2xbH4FIAPkYz1
ややこしいですがどんだけ大きな配列を入れようがランダムです。
適当に抜き出す
お手軽に
sub shuffle { return sort { int(rand 3) - 1 } @_ } print ((shuffle(0..9,A..Z,a..z))[0..9]); # iOKq7r1GL8
適当に並べ替えた奴の先頭から10個取ってるだけですね。簡単簡単。でも低ランダム。(元の配列の頭のほうばっかり取ってきます)
元の配列が抜き出したい数だけあるか分からないとき(上の例なら10個あるか分からないとき)は undef 抜くために
print grep { defined } ((shuffle(0..rand 9))[0..9]);
とかしましょう。元がundef入りの配列だと厄介だが。
かっつり
sub potluck { my @old = @{+shift}; local $_; my ($i, $new) = ($#old+1, 0); my $count = shift || int rand $i; $count = $i if $count > $i; map { $_ = $old[$new = rand $i--]; $old[$new] = $old[$i]; $_; } 0 .. $count-1 } print potluck([0..9,A..Z,a..z]); # hx9Py6m83ERG5JfarLqMeBwQozuZCYUv4i02KbntTDdpjs7NHgXO1WAI print potluck([0..9,A..Z,a..z],10); # o5fjvETbBJ
さっきのsub shuffleをちょっといじっただけです。配列のリファレンスを渡します。第2引数に抜き出したい数を渡すとその分だけ取ってきます。元の配列の大きさは超えません。
番外: List::Utilを使う
use List::Util qw(shuffle); print shuffle(0..9,A..Z,a..z); # 81D9moCj3n0zPO4VwIpGu5aFJR2ftTlyEgvxMHebhcXZYkqUiB6SWdAKrQNs7L
List::Utilはuseしただけでは関数をエクスポートしてくれないので使いたい関数は必ずインポートしましょう。
List::Utilはこれ以上ないくらい洗練されてる(と思う)のでv5.7.3以降のperlを使ってる人はこれ使うといいですね。
抜き出すのはないっぽいから自前で何とかしよう!
追記
さらに追記
Nyanna2011/06/05 09:47Home run! Great slgungig with that answer!
yikfqno2011/06/05 18:02NgKXa8 <a href="http://ytwaiwllkaqd.com/">ytwaiwllkaqd</a>
Lorren2011/06/05 21:19Your answer was just what I nedeed. Its made my day!
mpusalc2011/06/06 23:07fZNUyi , [url=http://fxmxjhkixatn.com/]fxmxjhkixatn[/url], [link=http://xlzdgbhgjqsh.com/]xlzdgbhgjqsh[/link], http://xffxfxayqpgo.com/
xicfqdqu2011/06/07 18:12VSQMgx <a href="http://ohsmkfuuaqow.com/">ohsmkfuuaqow</a>
hgucshczgpl2011/06/09 19:27zzfuU2 , [url=http://uiqorlryztty.com/]uiqorlryztty[/url], [link=http://keydymymivxx.com/]keydymymivxx[/link], http://ctmxknborxko.com/