• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • shuffle()

    (PHP 4, PHP 5, PHP 7)

    打乱数组

    说明

    shuffle(array &$array): bool

    本函数打乱(随机排列单元的顺序)一个数组。它使用的是伪随机数产生器,并不适合密码学的场合。

    Note:

    If two members compare as equal, their relative order in the sorted array is undefined.

    参数

    $array

    待操作的数组。

    返回值

    成功时返回TRUE,或者在失败时返回FALSE

    更新日志

    版本说明
    7.1.0内置的随机数产生算法从 libc rand 函数改成»梅森旋转伪随机数生成算法。

    范例

    Example #1shuffle()例子

    <?php
    $numbers = range(1, 20);
    shuffle($numbers);
    foreach ($numbers as $number) {
        echo "$number ";
    }
    ?>
    

    注释

    Note:此函数为$array中的元素赋与新的键名。这将删除原有的键名,而不是仅仅将键名重新排序。

    参见

    • array_rand() 从数组中随机取出一个或多个单元
    • 数组排序函数对比
    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.
    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;
    }
    ?>
    
    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...
    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!
    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;
    }
    ?>
    
    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
    )
    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
    )
    ?>
    
    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;
    }
    ?>
    
    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
    ?>
    
    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;>&hearts;</span>";
          $suits['Spade'][$j] = $cards[$j]."&spades;";
          $suits['Diamond'][$j] = $cards[$j]."<span style=color:#FF0000;>&diams;</span>";
          $suits['Club'][$j] = $cards[$j]."&clubs;";
        }
      }
      
      // 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>&emsp;$k1's<br />&emsp;{<br />&emsp;&emsp;";
        $acc = 0;
        
        // Display card value
        foreach($v1 as $k2 => $v2)
        {
          echo "$v2&nbsp";
          $acc++;
          
          if ($acc == 4)
          {
            echo "<br />&emsp;&emsp;";
            $acc = 0;
          }
        }
        echo "<br />&emsp;}</p>";
      }
    ?>
    
    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>';
    ?>
    
    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;
      }
    }
    ?>
    
    Here's a simple one liner for shuffling associative arrays:
    <?php
    uksort($myArray, function ($a, $b) {return mt_rand(-10, 10);});
    ?>
    
    It appears that the suhosin extensions >= 0.9.26 that have the suhosin.mt_srand.ignore and suhosin.srand.ignore settings set to "Off" do not affect shuffle().
    In other words, the only way I was able to get pseudo-random and predictable results through shuffle() was to disable the extension.
    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;
     }
    }
    ?>
    
    Just a quick note to let people know that shuffle() will work on multidimensional associative arrays provided that the first key is already numeric.
    So this array can be shuffled without losing any of the secondary keys or their values:
    $array[0]['color'], $array[0]['size'], $array[0]['fabric']
    . . .
    $array[50]['color'], $array[50]['size'], $array[50]['fabric']
    I recently ran up against needing to randomize this array and tried shuffle even though it's not really for associative arrays.
    Hope it helps somebody out there.
    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
    This function shuffles an associative array recursive.
    <?php
    /**
    * Shuffles an associative array recursive
    * @author Mogria <m0gr14@gmail.com>
    * @param array $array
    * @return array
    *
    */
    function rec_assoc_shuffle($array)
    {
     $ary_keys = array_keys($array);
     $ary_values = array_values($array);
     shuffle($ary_values);
     foreach($ary_keys as $key => $value) {
      if (is_array($ary_values[$key]) AND $ary_values[$key] != NULL) {
       $ary_values[$key] = rec_assoc_shuffle($ary_values[$key]);
      }
      $new[$value] = $ary_values[$key];
     }
     return $new;
    }
    ?>
    Example of use:
    <?php
    $array =
      Array(
        1,
        Array(
          1,
          2,
          3,
          4,
          Array(
            1,
            2,
            3,
            4,
            5
          )
        ),
        2,
        3,
        Array(
          0,
          1,
            Array(
              1,
              2,
              3,
              4,
                Array(
                  1,
                  6,
                  5,
                  2,
                  1,
                  3
                )
            )
        ),
        4,
        5,
        6,
        7
      );
    $array = rec_assoc_shuffle($array);
    echo '<pre>';
    print_r($array);
    echo '</pre>';
    /*
    Returns:
    Array
    (
      [0] => 6
      [1] => 5
      [2] => Array
        (
          [0] => 1
          [1] => 3
          [2] => Array
            (
              [0] => 3
              [1] => 1
              [2] => 2
              [3] => 4
              [4] => 5
            )
          [3] => 2
          [4] => 4
        )
      [3] => 3
      [4] => Array
        (
          [0] => Array
            (
              [0] => 3
              [1] => 1
              [2] => 4
              [3] => Array
                (
                  [0] => 5
                  [1] => 1
                  [2] => 3
                  [3] => 6
                  [4] => 1
                  [5] => 2
                )
              [4] => 2
            )
          [1] => 1
          [2] => 0
        )
      [5] => 2
      [6] => 1
      [7] => 4
      [8] => 7
    )
    */
    ?>
    
    Posted below is code that you would expect to work
    <?php
    $keys = shuffle(array_keys($arr));
    foreach ($keys as $key) {
     $arr_elem = $arr[$key];
     // do what you want with the array element
    }
    ?>
    This in fact does not work because shuffle returns a boolean true or false. More accurate code using this method would be:
    <?php
    $keys = array_keys($arr);
    shuffle($keys);
    foreach ($keys as $key) {
     $arr_elem = $arr[$key];
     // do what you want with the array element
    }
    ?>
    

    上篇:rsort()

    下篇:sizeof()