razvansg
razvansg

Reputation: 191

PHP shuffle like mysql order by rand(seed)

How do you shuffle an array in PHP but preserve the order of the shuffle when an element is inserted or deleted like mysql order by rand(seed) does? A kind of Fisher-Yates shuffle algorithm that ignores the length of the array.

Lets assume you have an array with A,B,C and you run this:

SELECT * 
FROM (
  SELECT 'A' AS value 
  UNION 
  SELECT 'B' AS value 
  UNION 
  SELECT 'C' AS value) AS T order by rand(123)

The result will be B,C,A.

Now if you add D to the list of elements:

SELECT * 
FROM (
  SELECT 'A' AS value 
  UNION 
  SELECT 'B' AS value 
  UNION 
  SELECT 'C' AS value 
  UNION 
  SELECT 'D' AS value) AS T order by rand(123)

The result will be D,B,C,A.

Adding element E to the list:

SELECT * 
FROM (
  SELECT 'A' AS value 
  UNION 
  SELECT 'B' AS value 
  UNION 
  SELECT 'C' AS value 
  UNION 
  SELECT 'D' AS value 
  UNION 
  SELECT 'E' AS value) AS T order by rand(123)

The result will be D,B,C,E,A.

Fisher-Yates will provide a totally different order when you add the element "D" to the array, while mysql order by rand(seed) will insert element "D" somewhere in the already random sorted list.

Upvotes: 1

Views: 561

Answers (1)

georg
georg

Reputation: 214949

You can mimic sort-by-rand behavior in a way similar to this:

function sort_by_rand($ary, $seed) {
    srand($seed);
    $tmp = array_map(function($x) { return [rand(), $x]; }, $ary);
    sort($tmp);
    return array_map(function($x) { return $x[1]; }, $tmp);
}

Results:

$ary = ['A', 'B', 'C'];
print_r(sort_by_rand($ary, 100)); // CBA

$ary = ['A', 'B', 'C', 'D'];
print_r(sort_by_rand($ary, 100)); // CBAD

$ary = ['A', 'B', 'C', 'D', 'E'];
print_r(sort_by_rand($ary, 100)); // CBAED

Upvotes: 3

Related Questions