lethalMango
lethalMango

Reputation: 4491

PHP Random Shuffle Array Maintaining Key => Value

I've been looking on google for the answer but can't seem to find something fool-proof and cant really afford to mess this up (going live into a production site).

What I have is an advanced search with 20+ filters, which returns an array including an ID and a Distance. What I need to do is shuffle these results to display in a random order every time. The array I have that comes out at the moment is:

Array (
    [0] => Array ( [id] => 1 [distance] => 1.95124994507577 )
    [1] => Array ( [id] => 13 [distance] => 4.75358968511882 )
    [2] => Array ( [id] => 7 [distance] => 33.2223233233323 )
    [3] => Array ( [id] => 21 [distance] => 18.2155453552336 )
    [4] => Array ( [id] => 102 [distance] = 221.2212587899658 )
)

What I need to be able to do is randomise or order of these every time but maintain the id and distance pairs, i.e.:

Array (
    [4] => Array ( [id] => 102 [distance] = 221.2212587899658 )
    [1] => Array ( [id] => 13 [distance] => 4.75358968511882 )
    [3] => Array ( [id] => 21 [distance] => 18.2155453552336 )
    [2] => Array ( [id] => 7 [distance] => 33.2223233233323 )
    [0] => Array ( [id] => 1 [distance] => 1.95124994507577 )
)

Thanks :)

Upvotes: 58

Views: 64084

Answers (10)

David Corp
David Corp

Reputation: 506

  $testArray = array('a' => 'apple', 'b' => 'ball', 'c' => 'cat', 'd' => 'dog');
  $keys = array_keys($testArray); //Get the Keys of the array -> a, b, c, d
  shuffle($keys); //Shuffle The keys array -> d, a, c, b
  $shuffledArray = array();
  foreach($keys as $key) {
    $shuffledArray[$key] = $testArray[$key]; //Get the original array using keys from shuffled array
  }
  print_r($shuffledArray);
  /*
  Array
  (
      [d] => dog
      [a] => apple
      [c] => cat
      [b] => ball
  )
  */

Upvotes: 1

Gautier
Gautier

Reputation: 1146

Answer using shuffle always return the same order. Here is one using random_int() where the order is different each time it is used:

function shuffle_assoc($array)
{
    while (count($array)) {
        $keys = array_keys($array);
        $index = $keys[random_int(0, count($keys)-1)];
        $array_rand[$index] = $array[$index];
        unset($array[$index]);
    }

    return $array_rand;
}

Upvotes: 0

Tom Kim
Tom Kim

Reputation: 534

I tried the most vote solution didn't popular shuffle list. This is the change I made to make it work. I want my array key starting from 1.

 $list = array_combine(range(1,10),range(100,110));
 $shuffle_list =  shuffle_assoc($list);


function shuffle_assoc($list)
{
    if (!is_array($list)) return $list;

    $keys = array_keys($list);
    shuffle($list);
    $random = array();
    foreach ($keys as $k => $key) {
        $random[$key] = $list[$k];
    }
    return $random;
}

Upvotes: -1

karim79
karim79

Reputation: 342635

The first user post under the shuffle documentation:

Shuffle associative and non-associative array while preserving key, value pairs. Also returns the shuffled array instead of shuffling it in place.

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; 
} 

Test case:

$arr = array();
$arr[] = array('id' => 5, 'foo' => 'hello');
$arr[] = array('id' => 7, 'foo' => 'byebye');
$arr[] = array('id' => 9, 'foo' => 'foo');
print_r(shuffle_assoc($arr));
print_r(shuffle_assoc($arr));
print_r(shuffle_assoc($arr));

Upvotes: 99

cwd
cwd

Reputation: 54776

Charles Iliya Krempeaux has a nice writeup on the issue and a function that worked really well for me:

function shuffle_assoc($array)
{
    // Initialize
        $shuffled_array = array();


    // Get array's keys and shuffle them.
        $shuffled_keys = array_keys($array);
        shuffle($shuffled_keys);


    // Create same array, but in shuffled order.
        foreach ( $shuffled_keys AS $shuffled_key ) {

            $shuffled_array[  $shuffled_key  ] = $array[  $shuffled_key  ];

        } // foreach


    // Return
        return $shuffled_array;
}

Upvotes: 3

Jake Wilson
Jake Wilson

Reputation: 91193

function shuffle_assoc($array)
{
    $keys = array_keys($array);
    shuffle($keys);
    return array_merge(array_flip($keys), $array);
}

Upvotes: 6

chaudruc
chaudruc

Reputation: 41

I was having a hard time with most of the answers provided - so I created this little snippet that took my arrays and randomized them while maintaining their keys:

function assoc_array_shuffle($array)
{
    $orig = array_flip($array);
    shuffle($array);
    foreach($array AS $key=>$n)
    {
        $data[$n] = $orig[$n];
    }
    return array_flip($data);
}

Upvotes: 3

v1r00z
v1r00z

Reputation: 796

Take a look to this function here :

     $foo = array('A','B','C'); 

 
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 */`enter code here`
    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;
  }

      shuffle_with_keys($foo);
      var_dump($foo);

Original post here : https://www.php.net/manual/en/function.shuffle.php#83007

Upvotes: 5

JesseBuesking
JesseBuesking

Reputation: 6586

Try using the fisher-yates algorithm from here:

function shuffle_me($shuffle_me) { 
   $randomized_keys = array_rand($shuffle_me, count($shuffle_me)); 
   foreach($randomized_keys as $current_key) { 
       $shuffled_me[$current_key] = $shuffle_me[$current_key]; 
   } 
   return $shuffled_me; 
} 

I had to implement something similar to this for my undergraduate senior thesis, and it works very well.

Upvotes: 2

Hamish
Hamish

Reputation: 23316

As of 5.3.0 you could do:

uksort($array, function() { return rand() > rand(); });

Upvotes: 24

Related Questions