shuffle
(PHP 4, PHP 5)
shuffle — Перемешать массив
Описание
bool shuffle
( array &$array
)
Эта функция перемещает элементы массива в случайном порядке.
Пример #1 Пример использования shuffle()
<?php
$numbers = range(1, 20);
srand((float)microtime() * 1000000);
shuffle($numbers);
while (list(, $number) = each($numbers)) {
echo "$number ";
}
?>
Замечание: Начиная с PHP 4.2.0, больше нет необходимости инициализировать генератор случайных чисел функциями srand() или mt_srand(), поскольку теперь это происходит автоматически.
См. также arsort(), asort(), ksort(), rsort(), sort() и usort().
- PHP Руководство
- Функции по категориям
- Индекс функций
- Справочник функций
- Расширения, относящиеся к переменным и типам
- Массивы
- array_change_key_case
- array_chunk
- array_column
- array_combine
- array_count_values
- array_diff_assoc
- array_diff_key
- array_diff_uassoc
- array_diff_ukey
- array_diff
- array_fill_keys
- array_fill
- array_filter
- array_flip
- array_intersect_assoc
- array_intersect_key
- array_intersect_uassoc
- array_intersect_ukey
- array_intersect
- array_key_exists
- array_keys
- array_map
- array_merge_recursive
- array_merge
- array_multisort
- array_pad
- array_pop
- array_product
- array_push
- array_rand
- array_reduce
- array_replace_recursive
- array_replace
- array_reverse
- array_search
- array_shift
- array_slice
- array_splice
- array_sum
- array_udiff_assoc
- array_udiff_uassoc
- array_udiff
- array_uintersect_assoc
- array_uintersect_uassoc
- array_uintersect
- array_unique
- array_unshift
- array_values
- array_walk_recursive
- array_walk
- array
- arsort
- asort
- compact
- count
- current
- each
- end
- extract
- in_array
- key_exists
- key
- krsort
- ksort
- list
- natcasesort
- natsort
- next
- pos
- prev
- range
- reset
- rsort
- shuffle
- sizeof
- sort
- uasort
- uksort
- usort
Коментарии
Another shuffle() implementation that preserves keys, does not use extra memory and perhaps is a bit easier to grasp.
<?php
if (function_exists('shuffle_with_keys')===false) {
function shuffle_with_keys(&$array) {
/* Auxiliary array to hold the new order */
$aux = array();
/* We work with an array of the keys */
$keys = array_keys($array);
/* We shuffle the keys */
shuffle($keys);
/* We iterate thru' the new order of the keys */
foreach($keys as $key) {
/* We insert the key, value pair in its new order */
$aux[$key] = $array[$key];
/* We remove the element from the old array to save memory */
unset($array[$key]);
}
/* The auxiliary array with the new order overwrites the old variable */
$array = $aux;
}
}
?>
Here is IMO the simplest and extremely fast way to shuffle an associative array AND keep the key=>value relationship. However, it ONLY works if there are NO NUMERIC keys AT ALL. Look into array_merge for the reason why.
<?php
$unshuffled = array('one'=>1,'two'=>2,'three'=>3);
$shuffled = array_merge( array_flip(array_rand($unshuffled,count($unshuffled))),$unshuffled );
?>
peace
If you want the Power Set (set of all unique subsets) of an array instead of permutations, you can use this simple algorithm:
<?php
/**
* Returns the power set of a one dimensional array,
* a 2-D array.
* array(a,b,c) ->
* array(array(a),array(b),array(c),array(a,b),array(b,c),array(a,b,c))
*/
function powerSet($in,$minLength = 1) {
$count = count($in);
$members = pow(2,$count);
$return = array();
for ($i = 0; $i < $members; $i++) {
$b = sprintf("%0".$count."b",$i);
$out = array();
for ($j = 0; $j < $count; $j++) {
if ($b{$j} == '1') $out[] = $in[$j];
}
if (count($out) >= $minLength) {
$return[] = $out;
}
}
return $return;
}
?>
Building on examples by m227 and pineappleclock, here is a function that returns all permutations of each set in the power set of an array of strings (instead of a string). Thanks for the great examples!
<?php
/*
Use: $arr = power_perms($in);
Example:
$in = array("A","B","C");
$power_perms = power_perms($in);
Returns:
Array
(
[0] => Array
(
[0] => A
[1] => B
[2] => C
)
[1] => Array
(
[0] => A
[1] => C
[2] => B
)
[2] => Array
(
[0] => B
[1] => A
[2] => C
)
[3] => Array
(
[0] => B
[1] => C
[2] => A
)
[4] => Array
(
[0] => C
[1] => A
[2] => B
)
[5] => Array
(
[0] => C
[1] => B
[2] => A
)
[6] => Array
(
[0] => A
[1] => B
)
[7] => Array
(
[0] => B
[1] => A
)
[8] => Array
(
[0] => B
[1] => C
)
[9] => Array
(
[0] => C
[1] => B
)
[10] => Array
(
[0] => A
[1] => C
)
[11] => Array
(
[0] => C
[1] => A
)
[12] => Array
(
[0] => A
)
[13] => Array
(
[0] => B
)
[14] => Array
(
[0] => C
)
)
*/
function power_perms($arr) {
$power_set = power_set($arr);
$result = array();
foreach($power_set as $set) {
$perms = perms($set);
$result = array_merge($result,$perms);
}
return $result;
}
function power_set($in,$minLength = 1) {
$count = count($in);
$members = pow(2,$count);
$return = array();
for ($i = 0; $i < $members; $i++) {
$b = sprintf("%0".$count."b",$i);
$out = array();
for ($j = 0; $j < $count; $j++) {
if ($b{$j} == '1') $out[] = $in[$j];
}
if (count($out) >= $minLength) {
$return[] = $out;
}
}
//usort($return,"cmp"); //can sort here by length
return $return;
}
function factorial($int){
if($int < 2) {
return 1;
}
for($f = 2; $int-1 > 1; $f *= $int--);
return $f;
}
function perm($arr, $nth = null) {
if ($nth === null) {
return perms($arr);
}
$result = array();
$length = count($arr);
while ($length--) {
$f = factorial($length);
$p = floor($nth / $f);
$result[] = $arr[$p];
array_delete_by_key($arr, $p);
$nth -= $p * $f;
}
$result = array_merge($result,$arr);
return $result;
}
function perms($arr) {
$p = array();
for ($i=0; $i < factorial(count($arr)); $i++) {
$p[] = perm($arr, $i);
}
return $p;
}
function array_delete_by_key(&$array, $delete_key, $use_old_keys = FALSE) {
unset($array[$delete_key]);
if(!$use_old_keys) {
$array = array_values($array);
}
return TRUE;
}
?>
Here i wrote a custom shuffle function which preserves the array index and distributes the array element randomly.
<?php
/*
* return an array whose elements are shuffled in random order.
*/
function custom_shuffle($my_array = array()) {
$copy = array();
while (count($my_array)) {
// takes a rand array elements by its key
$element = array_rand($my_array);
// assign the array and its value to an another array
$copy[$element] = $my_array[$element];
//delete the element from source array
unset($my_array[$element]);
}
return $copy;
}
$array = array(
'a' => 'apple',
'b' => 'ball',
'c' => 'cat',
'd' => 'dog',
'e' => 'egg',
'f' => 'fan',
'g' => 'gun'
);
print_r(custom_shuffle($array));
Array
(
[c] => cat
[e] => egg
[f] => fan
[a] => apple
[b] => ball
[g] => gun
[d] => dog
)
?>
I've been wondering why shuffle() doesn't provide the shuffled array as a return value instead of a bool. I mean, what could possibly go wrong in shuffling elements from an array?
So I use something like this:
<?php
function array_shuffle($array) {
if (shuffle($array)) {
return $array;
} else {
return FALSE;
}
}
?>
I needed a simple function two shuffle a two dimensional array. Please note the second level arrays must be indexed using integers, for example $myarray[0]["Name"] and not $myarray["One"]["Name"]. Here is the function:
<?php
function twodshuffle($array)
{
// Get array length
$count = count($array);
// Create a range of indicies
$indi = range(0,$count-1);
// Randomize indicies array
shuffle($indi);
// Initialize new array
$newarray = array($count);
// Holds current index
$i = 0;
// Shuffle multidimensional array
foreach ($indi as $index)
{
$newarray[$i] = $array[$index];
$i++;
}
return $newarray;
}
?>
Please note it only works on two dimensional arrays. Here is an example:
<?php
$myarray = array("Google" => array("Name" => "Google", "URL" => "www.google.com", "Usage" => "Googling"), "Yahoo" => array("Name" => "Yahoo", "URL" => "www.yahoo.com", "Usage" => "Yahooing?"), "Ask" => array("Name" => "Ask", "URL" => "www.ask.com", "Usage" => "Asking Jeeves"));
print_r(twodshuffle($myarray));
/* And the result is:
Array ( [0] => Array ( [Name] => Ask [URL] => www.ask.com [Usage] => Asking Jeeves ) [1] => Array ( [Name] => Google [URL] => www.google.com [Usage] => Googling ) [2] => Array ( [Name] => Yahoo [URL] => www.yahoo.com [Usage] => Yahooing? ) )
*/
?>
Hope you find it useful!
shuffle for associative arrays, preserves key=>value pairs.
(Based on (Vladimir Kornea of typetango.com)'s function)
<?php
function shuffle_assoc(&$array) {
$keys = array_keys($array);
shuffle($keys);
foreach($keys as $key) {
$new[$key] = $array[$key];
}
$array = $new;
return true;
}
?>
*note: as of PHP 5.2.10, array_rand's resulting array of keys is no longer shuffled, so we use array_keys + shuffle.
Here is a quick function I wrote that generates a random password and uses shuffle() to easily shuffle the order.
<?php
public function randPass($upper = 3, $lower = 3, $numeric = 3, $other = 2) {
//we need these vars to create a password string
$passOrder = Array();
$passWord = '';
//generate the contents of the password
for ($i = 0; $i < $upper; $i++) {
$passOrder[] = chr(rand(65, 90));
}
for ($i = 0; $i < $lower; $i++) {
$passOrder[] = chr(rand(97, 122));
}
for ($i = 0; $i < $numeric; $i++) {
$passOrder[] = chr(rand(48, 57));
}
for ($i = 0; $i < $other; $i++) {
$passOrder[] = chr(rand(33, 47));
}
//randomize the order of characters
shuffle($passOrder);
//concatenate into a string
foreach ($passOrder as $char) {
$passWord .= $char;
}
//we're done
return $passWord;
}
?>
Many people in SEO need to supply an array and shuffle the results and need the same result each time that page is generated. This is my implementation with a working example:
<?php
function seoShuffle(&$items,$string) {
mt_srand(strlen($string));
for ($i = count($items) - 1; $i > 0; $i--){
$j = @mt_rand(0, $i);
$tmp = $items[$i];
$items[$i] = $items[$j];
$items[$j] = $tmp;
}
}
$items = array('one','two','three','four','five','six');
$string = 'whatever';
echo '<pre>';
print_r($items);
echo '</pre>';
seoShuffle($items,$string);
echo '<pre>';
print_r($items);
echo '</pre>';
?>
This is a replica of shuffle() but preserving keys (associative and non-associative)
bool kshuffle ( array &$array )
<?php
function kshuffle(&$array) {
if(!is_array($array) || empty($array)) {
return false;
}
$tmp = array();
foreach($array as $key => $value) {
$tmp[] = array('k' => $key, 'v' => $value);
}
shuffle($tmp);
$array = array();
foreach($tmp as $entry) {
$array[$entry['k']] = $entry['v'];
}
return true;
}
$array = array('first' => 0, 'second' => 1, 'third' => 2);
kshuffle($array);
print_r($array); // [second] => 1 [first] => 0 [third] => 2
$array = array('first', 'second', 'third');
kshuffle($array);
print_r($array); // [1] => second [2] => third [0] => first
?>
Shuffle associative and non-associative array while preserving key, value pairs. Also returns the shuffled array instead of shuffling it in place.
<?php
function shuffle_assoc($list) {
if (!is_array($list)) return $list;
$keys = array_keys($list);
shuffle($keys);
$random = array();
foreach ($keys as $key)
$random[$key] = $list[$key];
return $random;
}
?>
Copy and paste this script and refresh the page to see the shuffling effect.
<?php
/**
* Shuffles and displays cards in a deck
* @author: Eric Anderson
* @filename: deckofcards.php
*/
// Create an array of face values
// and an array of card values
// then merge them together
$cards = array_merge(array("J", "Q", "K", "A"), range(2,10)); // 13 cards
// Shuffle the cards
shuffle($cards);
// Create an multidimentional array to hold the 4 suits
$suits = array(
'Heart' => array(),
'Spade' => array(),
'Diamond' => array(),
'Club' => array()
);
// Add cards to their respective suits
for($i = 0; $i < count($suits); $i++)
{
for($j = 0; $j < count($cards); $j++)
{
$suits['Heart'][$j] = $cards[$j]."<span style=color:#FF0000;>♥</span>";
$suits['Spade'][$j] = $cards[$j]."♠";
$suits['Diamond'][$j] = $cards[$j]."<span style=color:#FF0000;>♦</span>";
$suits['Club'][$j] = $cards[$j]."♣";
}
}
// Create a deck
$deck = array();
// Merge the suits into the empty deck array
$deck = array_merge($deck, $suits);
// Display the deck to the screen
echo "<p><b>Deck of cards:</b></p>";
foreach($deck as $k1 => $v1)
{
// Display suit name
echo "<p> $k1's<br /> {<br />  ";
$acc = 0;
// Display card value
foreach($v1 as $k2 => $v2)
{
echo "$v2 ";
$acc++;
if ($acc == 4)
{
echo "<br />  ";
$acc = 0;
}
}
echo "<br /> }</p>";
}
?>
This seems to do reasonably well as a shuffle() that preserves index assocation:
<?php
function ashuffle (&$arr) {
uasort($arr, function ($a, $b) {
return rand(-1, 1);
});
}
?>
Obviously only works if PHP has closures enabled...
There is an function which uses native shuffle() but preserves keys, and their order, so at end, only values are shuffled.
<?PHP
/**
* Array Quake - Give an array good quake so every value will endup with random given space.
* Keys, and their order are preserved.
* @author xZero <xzero@elite7hackers.net>
* @param array $array
* @return boolean false on failure
*/
function array_quake(&$array) {
if (is_array($array)) {
$keys = array_keys($array); // We need this to preserve keys
$temp = $array;
$array = NULL;
shuffle($temp); // Array shuffle
foreach ($temp as $k => $item) {
$array[$keys[$k]] = $item;
}
return;
}
return false;
}
// Example
$numbers = array(
'ZERO' => 0,
'ONE' => 1,
'TWO' => 2,
'THREE' => 3,
'FOUR' => 4,
'FIVE' => 5,
'SIX' => 6,
'SEVEN' => 7,
'EIGHT' => 8,
'NINE' => 9
);
echo "\nBefore (original):\n";
print_r($numbers);
array_quake($numbers);
echo "\n\nAfter (Array Quake);\n";
print_r($numbers);
echo "\n";
?>
Result example:
Before (original):
Array
(
[ZERO] => 0
[ONE] => 1
[TWO] => 2
[THREE] => 3
[FOUR] => 4
[FIVE] => 5
[SIX] => 6
[SEVEN] => 7
[EIGHT] => 8
[NINE] => 9
)
After (Array Quake);
Array
(
[ZERO] => 4
[ONE] => 2
[TWO] => 0
[THREE] => 8
[FOUR] => 3
[FIVE] => 6
[SIX] => 1
[SEVEN] => 7
[EIGHT] => 5
[NINE] => 9
)
implementation of shuffle() using random_int()
<?php
function random_int_shuffle ( array $array ): array
{
$array = array_values($array);
$result = [];
$skip_indexes = [];
$sizeof_array = count($array);
for ( $i = 0; $i < $sizeof_array; $i++ )
{
do
{
$random_index = random_int(0, $sizeof_array);
} while ( in_array($random_index, $skip_indexes) );
$skip_indexes[] = $random_index;
$result[] = $array[$random_index];
}
return $result;
}
?>