Shuffling arrays in PHP

Recently, while working on a portfolio searching system I faced one problem with displaying results. It turned out that portfolios of same users appear close to one another. This was not good as I wanted to show variety of different users portfolios on a search result page. Therefore I needed to shuffle them somehow. Generally, in PHP there are three ways to shuffle arrays:

  • Random array shuffle
  • Non random index shuffle – array indices are always re-organized in the same way
  • Non random value shuffle – shuffle result depending on array values

Random array shuffle

This can be done with php core shuffle() function in following way:

$data = array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I');
shuffle($data);
var_dump($data);

Each time this function is called, results of shuffle will be different. Therefore this method in my case wasn’t very useful.

Non random index shuffle

This method turned to be best solution as I wanted to re-organize searching results always in the same, static way.
I did some research and I find out that the best method is point reflection of odd indices of an array. It guarantees the results will be shuffled and evenly distributed across the array.
Let’s imagine we’ve got one dimensional array and we display it in a two dimensional grid. Shuffle algorithm will do as follows:

array shuffle

Let’s see how looks like code:

function array_shuffle(array $data) {
    if (empty($data) || count($data) < 3) return $data;
    $length = count($data);
    // for each odd indices
    for ($i = 1; $i < floor($length / 2); $i += 2) {
        // replace item from current index with 
        // corresponding item in the end of an array
        $tmp = $data[$length - 1 - $i];
        $data[$length - 1 - $i] = $data[$i];
        $data[$i] = $tmp;
    }
    // reset array indices
    return array_values($data);
}

// usage
$data = array(
    'A', 'B', 'C', 
    'D', 'E', 'F', 
    'G', 'H', 'I'
);

var_dump(array_shuffle($data));

In case of higher dimensions, all we have to do is to flatten an array into one-dimensional list using following function:

function array_flatten(array $array) {
    $flatten = array();
    array_walk_recursive($array, function($value) use(&$flatten) {
        $flatten[] = $value;
    });
    return $flatten;
}

$multiDimensionalArray = array(...);
$flatArray = array_flatten($multiDimensionalArray);

var_dump(array_shuffle($flatArray));

And that’s all!