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); ?>
(PHP 4, PHP 5, PHP 7, PHP 8)
array_rand — Escolhe uma ou mais chaves aleatórias de um array
Escolhe aleatóriamente um ou mais itens de um array, e retorna a chave (ou chaves) do itens selecionados.
Esta função não gera valores criptograficamente seguros e não deve ser usada para propósitos criptográficos ou fins que exijam que os valores retornados sejam impossíveis de adivinhar.
Se aleatoriedade criptograficamente segura for necessária, a classe Random\Randomizer pode ser usada com o mecanismo Random\Engine\Secure. Para casos de uso simples, as funções random_int() e random_bytes() fornecem uma API conveniente e segura que é garantida pelo CSPRNG do sistema operacional.
array
O array de entrada.
num
Especifica quantos elementos deseja obter.
Se estiver selecionando apenas um elemento, array_rand() retorna
a chave para este elemento aleatório. De outra forma, ele retorna um array com as chaves desses
elementos selecionados. Assim é possível selecionar os elementos pelas chaves
no array assim como valores aleatórios. Se múltiplas chaves forem retornadas,
elas serão retornadas na ordem em que estavam presentes no array original.
Tentar selecionar mais elementos
que a quantidade presente no array resultará em um erro
E_WARNING
, e NULL será retornado.
Versão | Descrição |
---|---|
7.1.0 | O algoritmo de embaralhamento interno foi alterado para usar o Gerador de Números Aleatórios » Mersenne Twister em vez da função rand da libc. |
Exemplo #1 Exemplo de array_rand()
<?php
$input = array("Neo", "Morpheus", "Trinity", "Cypher", "Tank");
$rand_keys = array_rand($input, 2);
echo $input[$rand_keys[0]] . "\n";
echo $input[$rand_keys[1]] . "\n";
?>
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); ?>
It doesn't explicitly say it in the documentation, but PHP won't pick the same key twice in one call.
<?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)]);
}
<?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 ) ) ) ) );
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.
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)
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
)
*/