Perlで配列をシャッフルする

このところ、ソートばっかりやってて相当(*1)疲れたので、
たまには逆にシャッフルしてみようと思う。

結論から言うと、Array::Shuffleを使えばいんだけど、
その前に、いくつか実装してみた。

乱数をソートしてシャッフル

use strict;
use warnings;
use v5.10;

my @data = 1..9;
@data = map  { $_->[0]; }
        sort { $a->[1] <=> $b->[1] }
        map  { [ $_, rand ]; } @data;

say join( ', ', @data );

実行結果はこんな感じ。
$ perl aaa.pl
8, 4, 2, 3, 1, 9, 6, 5, 7

これは、シャッフルしたいデータと乱数をペアにして、
ペアにした乱数でソートした後、シャッフルしたデータのみに変換している。
無駄にソートしなきゃいけない分、ちょっと微妙。

ランダムに選択した添え字同士でシャッフル

use strict;
use warnings;
use v5.10;

my @data = 1..9;
my $n = scalar @data;
for ( 1..100 ) {
    my ( $a, $b ) = ( int(rand $n), int(rand $n) );
    @data[$a,$b] = @data[$b,$a];
}

say join( ', ', @data );

実行結果はこんな感じ。
$ perl bbb.pl
8, 4, 5, 3, 6, 2, 1, 7, 9

これだと、任意の回数だけシャッフルできるんだけど、
randを一度に2回呼ぶあたりが微妙。

先頭から順にランダムに選択した添え字でシャッフル

use strict;
use warnings;
use v5.10;

my @data = 1..9;
my $n = scalar @data;
foreach my $i ( 0..($n - 1) ) {
    my $j = int( rand $n );
    @data[$i,$j] = @data[$j,$i];
}

say join( ', ', @data );

実行結果はこんな感じ。
$ perl ccc.pl
2, 4, 1, 8, 7, 3, 5, 9, 6

これは、metacpan.orgで、そのものズバリ”array shuffle”で検索して出てきた、
Array::Shuffleを見ながら実装した。
これを何回か繰り返せばいんじゃないですかね。

Array::Shuffleを使ってシャッフル

use strict;
use warnings;
use v5.10;
use Array::Shuffle qw(shuffle_array);

my @data = 1..9;
shuffle_array( @data );

say join( ', ', @data );

実行結果はこんな感じ。
$ perl ddd.pl
9, 2, 6, 8, 3, 4, 1, 5, 7

特に説明する必要ないですね。
XSで書かれてるようなので、環境によっては使えないかもですが、
その場合は、一つ前に紹介したのを使う感じで。

あと、気付いた方も居ると思いますが、
実行結果は見ても「シャッフルされてるねー」、以上のアレはないデス。

おしまい。

(*1) ソートだけに。

Leave a Comment