[PHP] 配列からランダムに値を取得する

公開

スポンサーリンク

PHPで配列をランダムに並べ替える、あるいはランダムに値を取得する方法のまとめです。

そんなん簡単だろーと思っていたのですが、配列の形式や、求められる取得要件によって、採るべき方法が変わり、結構いろいろなパターンがあるのですね。

配列中からランダムに値を取得するパターンは以下の場合に分けられるかと思います。

  1. 配列からランダムに値を1つだけ取得
  2. 配列からランダムに値を2以上取得、取得対象が重複してもOK
  3. 配列からランダムに値を2以上取得、取得対象が重複してはならない

配列と連想配列の場合は同じやり方で対応可能なので分けません。

PHPには配列からランダムにキーを取得するarray_rand()と、配列をシャッフルしランダムに並べ替えてくれるshuffle()という2つの関数があります。この2つを組み合わせることで、基本的には全ての用途に対応可能です。

どちらか1つでたいていのことに対応できるだろうと思ったら、案外そうでもなく、しかしながら両者がそろえば配列のランダム用途は全てに対応可能という補完関係になっているわけです。

配列からランダムに値を1つだけ取得

array_rand()は配列からキーをランダムに取り出してくれる関数です。

$hash = array('Apple', 'Orange', 'Grape' );
$key = array_rand($hash);// 0/1/2のどれか
echo $hash[$key];// Apple/Orange/Grapeのどれか

配列中から1つだけ値をランダムに取得したい場合はこのコードで事足ります。

配列が連想配列ではなく、キーが0から順番に振られているという前提なら、

$hash[ array_rand(0, count($hash)-1) ];
という方法もあります。とはいえ、前者のコードの方が配列の形式を問わないのでいいように思います。

配列からランダムに値を2個以上取得、取得対象が重複してもOK

この場合は上記の「配列からランダムに値を1つだけ取得」を繰り返すだけなので、特に工夫はいりません。ランダムに5回、配列から値を取り出すなら以下のように、単にループさせれば終わりです。

$hash = array('Apple', 'Orange', 'Grape' );
for ($i=0;$i<5;$i++) {
  $key = array_rand($hash);// 0/1/2のどれか
  echo $hash[$key];// Apple/Orange/Grapeのどれか
}

なお、array_rand()はキーの取得数を第2引数に指定可能です。なので、複数の値を配列からランダムに取り出す際、この方法を使えば良いと思うかもしれませんが、避けたほうが良いと思います。

array_rand()の第2引数を使った複数キーの取得は、結構クセがあるからです。

まず、第2引数を2以上にすると返り値が配列型になってしまいます。1だと返り値はint型です。

var_dump( array_rand($hash, 2) );// array(2)

これでは型によって異なる対応のコードを書かねばならず、煩雑になってしまいます。

また、第2引数を複数とした場合の返り値は、必ず昇順となってしまいます。どういうことかというと、キーが0, 1, 2である要素数3の配列からランダムに2つのキーを取り出したなら、本来組み合わせは0/1, 0/2, 1/2, 1/0, 2/0, 2/1の6パターンです。ところが、array_rand()が返してくるキーは0/1, 0/2, 1/2の3パターンだけとなります。そのため、第2引数を使う方法ではちゃんとしたランダムな取得にならないのです。

配列からランダムに値を2以上取得、取得対象が重複してはならない

この場合、array_rand()shuffle()を使います。array_rand()でまず指定した数のキーを取得します。この時、キーの順は前段で述べたように、昇順となり、中途半端なランダムになっています。そこで、配列の順をシャッフルするshuffle()で取得したキー配列をランダムに並べ替えます。

$hash = array('Apple', 'Orange', 'Grape' );
$keys = array_rand($hash, 2 );
shuffle($keys);
foreach ($keys as $key ) {
  echo $hash[$key];// Apple/Orange/Grapeのどれか
}

これで配列からランダムに値を取得することに成功しました。

この場合ですが、キーの取得にarray_rand()ではなくarray_keys()を使ってもいいかもしれません。array_keys()でキー全てを取得してからshuffle()に通し、それからfor文で指定した数を配列からランダムに取得するという手順です。

$hash = array('Apple', 'Orange', 'Grape' );
$cnt = 2;// 取得数
$keys = array_keys($hash);
shuffle($keys);
for ($i=0;$i<$cnt;$i++ ) {
  echo $hash[$keys[$i]];// Apple/Orange/Grapeのどれか
}

このコードなら取得する数が1個の場合にも対応しているので、場合によってはこちらの方が良いかもしれません。

スポンサーリンク


Comment


  1. ななし : 投稿日:2015年3月3日 2:28 PM

    シャッフルしたんだから、先頭から欲しいだけとればいいのに