PHPには'shuffle'というその名の通り配列をシャッフルしてくれる関数がある。
例えば以下のようなコードがあったとしたら

<?php
$numbers = range(1, 5);
shuffle($numbers);
print_r($numbers);
?>

こんな感じでシャッフルされる

Array
(
    [0] => 2
    [1] => 4
    [2] => 5
    [3] => 3
    [4] => 1
)

たまにこういった処理が必要になるが他の言語ではどうすればいいか?

Pythonでは

import random
def shuffle(li):
    rl = []
    while (len(li)):
        rl.append(a.pop(int(random.random() * len(a))))
    return rl

こんな感じの関数で配列がシャッフルされる。
'random'モジュールをインポートしなければいけないところがちょっと面倒くさいが、Pythonが面白いのはpop関数に任意の引数を与えることでその引数が添字になっている要素を返してくれるところだ。
そのおかげでPythonにはshift関数がいらない。単純に

pop(0)

こう書くだけでshiftの代わりになるからだ。
PerlやPHP、Rubyなどの言語はpop関数はあくまで配列の最後の要素を返すだけだ。 ただ、このrandomモジュールにはその名も'shuffle'という関数が存在し上のような関数を書かずとも

import random
li = [1,2,3,4,5]
random.shuffle(li)

こう書くだけで配列(リスト)をランダムに並べ替えてくれる。
この時、元の配列自体が並べ替えられるのでちょっと注意が必要。'random.shuffle()'関数自体は何も値を返してこない

Javascriptだと

function shuffle(list) {
  var i = list.length;

  while (--i) {
    var j = Math.floor(Math.random() * (i + 1));
    if (i == j) continue;
    var k = list[i];
    list[i] = list[j];
    list[j] = k;
  }

  return list;
}

Perlだと

sub shuffle {
  my $array = shift;
  my $i;
  for ($i = @$array; --$i; ) {
    my $j = int rand ($i+1);
    next if $i == $j;
    @$array[$i,$j] = @$array[$j,$i];
  }
}

と、こんなコードで配列はシャッフルされる。
上のコードだと、Perlの関数は引数には配列そのものではなく、参照を渡さなくては駄目だ。
とはいえ、このコードだとどうもすべての組み合わせを同じ確率で生成することはできないようだ(Perlクックブックに書いてあった)。 Perlの場合はより偏りがなく、且つ簡単にシャッフルするには

use List::Util qw/shuffle/;
@a = shuffle(1,2,3,4,5);

と、モジュールをuseすればいい。

Rubyには、そういった処理のイディオムが既に存在するようで

a=[1,2,3,4,5]
a.sort_by{rand}

と、こうするだけでいい。
Rubyは既存のクラス(HashやString)にメソッドを追加したり上書きしたりすることも簡単にできるので

class Array
  def shuffle
    sort_by{rand}
  end
end 

このコードを追加するだけでArrayクラスに'shuffle'メソッドが追加される。後は

a=[1,2,3,4,5]
a.shuffle

こうするだけでいくらでもシャッフルされた配列を得ることが出来る

カテゴリ:

トラックバック(0)

トラックバックURL: http://blog.beanz-net.jp/beanz_mtos/mt-tb.cgi/70

コメントする