PHP 8.3.4 Released!

array_rand

(PHP 4, PHP 5, PHP 7, PHP 8)

array_rand配列から一つ以上のキーをランダムに取得する

説明

array_rand(array $array, int $num = 1): int|string|array

一つ以上のランダムなエントリを配列から取り出し、 取り出したエントリのキーを返します。

警告

この関数が生成する値は、暗号学的にセキュアではありません。そのため、これを暗号や、戻り値を推測できないことが必須の値として使っては いけません

暗号学的にセキュアな乱数が必要な場合は、Random\RandomizerRandom\Engine\Secure と一緒に使いましょう。簡単なユースケースの場合、random_int()random_bytes() 関数が、オペレーティングシステムの CSPRNG を使った、 便利で安全な API を提供します。

パラメータ

array

入力の配列。 空配列にはできません。

num

取得するエントリの数を指定します。 1以上 array の要素数以下である必要があります。

戻り値

エントリを一つだけ取得する場合、 array_rand() はランダムなエントリのキーを返します。 その他の場合は、ランダムなエントリのキーの配列を返します。 これにより、ランダムな値だけではなくランダムなキーも配列から取得できるようになります。 複数のキーが返される場合、配列に格納された順番と同じ順で返されます。

エラー / 例外

array が空か num が範囲外の値の場合に、 ValueError がスローされます。

変更履歴

バージョン 説明
8.0.0 num が範囲外の値の場合に、 ValueError がスローされるようになりました。 これより前のバージョンでは、 E_WARNING が発生し、null を返していました。
8.0.0 array が空の場合に、 ValueError がスローされるようになりました。 これより前のバージョンでは、 E_WARNING が発生し、null を返していました。
7.1.0 内部的なランダム化アルゴリズムは、 libc の rand 関数ではなく、 » メルセンヌツイスタ 乱数生成器を使うように 変更されました

例1 array_rand() の例

<?php
srand
((float) microtime() * 10000000);
$input = array("ネオ", "モーフィアス", "トリニティ", "サイファー", "タンク");
$rand_keys = array_rand($input, 2);
echo
$input[$rand_keys[0]] . "\n";
echo
$input[$rand_keys[1]] . "\n";
?>

注意

注意: srand() または mt_srand() によりランダム数生成器にシードを与える必要はありません。 これは、この処理が自動的に行われるためです。

参考

add a note

User Contributed Notes 7 notes

up
92
Anonymous
14 years ago
If the array elements are unique, and are all integers or strings, here is a simple way to pick $n random *values* (not keys) from an array $array:

<?php array_rand(array_flip($array), $n); ?>
up
67
Anonymous
11 years ago
It doesn't explicitly say it in the documentation, but PHP won't pick the same key twice in one call.
up
22
grzeniufication
6 years ago
<?php

/**
* Wraps array_rand call with additional checks
*
* TLDR; not so radom as you'd wish.
*
* NOTICE: the closer you get to the input arrays length, for the n parameter, the output gets less random.
* e.g.: array_random($a, count($a)) == $a will yield true
* This, most certainly, has to do with the method used for making the array random (see other comments).
*
* @throws OutOfBoundsException – if n less than one or exceeds size of input array
*
* @param array $array – array to randomize
* @param int $n – how many elements to return
* @return array
*/
function array_random(array $array, int $n = 1): array
{
if (
$n < 1 || $n > count($array)) {
throw new
OutOfBoundsException();
}

return (
$n !== 1)
?
array_values(array_intersect_key($array, array_flip(array_rand($array, $n))))
: array(
$array[array_rand($array)]);
}
up
10
grzeniufication
6 years ago
<?php
// An example how to fetch multiple values from array_rand
$a = [ 'a', 'b', 'c', 'd', 'e', 'f', 'g' ];
$n = 3;

// If you want to fetch multiple values you can try this:
print_r( array_intersect_key( $a, array_flip( array_rand( $a, $n ) ) ) );

// If you want to re-index keys wrap the call in 'array_values':
print_r( array_values( array_intersect_key( $a, array_flip( array_rand( $a, $n ) ) ) ) );
up
2
fulachan2 at gmail dot com
2 years ago
array_rand () takes a random value without ever being able to go back in its choice of random value.
A simple example:
I decide to mix an array of 10 entries to retrieve 3 values. This choice will give increasing and random values.

$myarray = range(1,10);

$pm = array_rand($myarray,3);
// $pm return array(0->0,1->6,2->8)

But if I decide to shuffle an array of 10 entries to get 10 entries, array_rand () will choose to assign a value to each return value and therefore the return array will not be random.

$gm = array_rand($myarray,count($myarray));
// $gm not random array(0->0,1->1,2->2,3->3,4->4,5->5,6->6,7->7,8->8,9->9)

The easiest way to have a truly random value:
either use array_rand () in a loop of 1 value at a time

$deg = range(-60,60);
$size = range(16,64);
$color = ["blue","red","green","pink","orange","purple","grey","darkgreen","darkkhaki"];
$i = 0;
$longueur = 10;
do{
++$i;
printf("<span style='transform: rotateZ(%ddeg); display: inline-block;font-size: %spx; color:%s'>%s</span>",
$deg[array_rand($deg)],
$size[array_rand($size)],
$color[array_rand($color)],
$alnum[array_rand($alnum)]);

}while($i < $longueur);

------------------
or simply use shuffle () to shuffle the array really randomly.
up
1
divinity76+spam at gmail dot com
1 year ago
for a cryptographically secure version, try

<?php

/**
* fetch a random key from array, using a cryptograpically secure rng
* discussed+reviewed at https://codereview.stackexchange.com/questions/275832/cryptographically-secure-version-of-the-core-array-rand-function/
*
* @param array $array
* @throws ValueError if array is empty
* @return int|string key
*/
function array_rand_cryptographically_secure(array $array)/*: int|string*/ {
$max = count ( $array ) - 1;
if (
$max < 0) {
throw new
ValueError ( 'Argument #1 ($array) cannot be empty' );
}
return
key ( array_slice ( $array, random_int ( 0, $max ), 1, true ) );
}

$tests = [
[
5, 6, 7],
[
'a' => 1, 'b' => 2, 'c' => 3],
[
'zero', 4 => 'four', 9 => 'nine'],
[
"PEAN"=>0],
[]
];
foreach (
$tests as $test) {
echo
array_rand_cryptographically_secure($test) . "\n";
}

?>
(this is an improved version, which unlike the first version, avoids copying *all* the keys)
up
-8
Vitaly
2 years ago
Generate random index in weights array.
Implementation of Vose's Alias Method.

<?php
class AliasMethod
{
protected
$count;
protected
$prob;
protected
$alias;

public function
__construct($weight)
{
$count = count($weight);
$sum = array_sum($weight);
$d = $count / $sum;
$small = [];
$large = [];

foreach (
$weight as $i => & $w) {
if ( (
$w *= $d) < 1)
$small[] = $i;
else
$large[] = $i;
}
unset(
$w);

$prob = [];
$alias = [];

while (!empty(
$small) AND !empty($large)) {
$l = array_pop($small);
$g = array_pop($large);
$prob[$l] = $weight[$l];
$alias[$l] = $g;

if ( (
$weight[$g] += $weight[$l] - 1) < 1)
$small[] = $g;
else
$large[] = $g;
}

foreach (
$large as $i)
$prob[$i] = 1;

foreach (
$small as $i)
$prob[$i] = 1;

$this->prob = $prob;
$this->alias = $alias;
$this->count = $count;

}

public function
next(): int
{
$i = mt_rand(0, $this->count - 1);
if (
mt_rand() / mt_getrandmax() <= $this->prob[$i])
return
$i;
else
return
$this->alias[$i];
}
}

// Usage:

$weight = [1, 2, 1, 1, 100, 1, 1, 5, 1, 1];
$rnd = new AliasMethod($weight);

$results = array_fill(0, count($weight), 0);

for(
$i = 0; $i < 100000; ++$i) {
$results[$rnd->next()]++;
}
print_r($results);

/*
Array
(
[0] => 901
[1] => 1785
[2] => 899
[3] => 907
[4] => 87655
[5] => 867
[6] => 836
[7] => 4371
[8] => 910
[9] => 869
)
*/
To Top