Search code examples
phparrayssortingshufflename-collision

Sorting a list of names randomly to create a second list(map) based on 2 restriction


I have a list of names:

$array = array(
    "Alberto",  
    "Bianca",  
    "Claudio",  
    "Douglas",
    "Erica"
);

I would like to sort this list randomly to generate an array_map like this:

$array = array(
    "Alberto" => "Claudio",  
    "Bianca" => "Erica",  
    "Claudio" => "Douglas",  
    "Douglas"  => "Bianca",
    "Erica" => "Alberto"
);

There are 2 restrictions:

  1. A name cannot be assigned to itself, for example "Claudio" => "Claudio".

  2. The sort must not have different results. In other words, if it generates a result for the first time it runs, all other times it runs, it must generate the same result.

I am thinking to use some type of hash checking, but this will not guarantee that a name will be assigned to itself.

I tried to use

rsort($array);

But this will not work if the number of elements in the array is odd, in my example, I will have problems in the line

"Claudio" => "Claudio"

Is there any way to sort this list of names that will not break the 2 restrictions?


Solution

  • How about a "deck cut"? IOW, move half of the elements to the back. This will be consistent and will not "break". The only consideration is that, you may wish to throw an exception if the number of elements is less than 2 (impossible to modify).

    array_splice() only takes integer values in param 2 and 3, so if the count is odd, the number will be truncated/floored. This logic ensures that you will never have any key-value collisions.

    Code: (Demo)

    $arrays = [
        ["Alberto"],
        ["Alberto", "Bianca"],
        ["Alberto", "Bianca", "Claudio"],
        ["Alberto", "Bianca", "Claudio", "Douglas"],
        ["Alberto", "Bianca", "Claudio", "Douglas", "Erica"]
    ];
    
    foreach ($arrays as $array) {
        $original = $array;
        array_push($array, ...array_splice($array, 0, count($array) / 2));
        var_export(array_combine($original,$array));
        echo "\n---\n";
    }
    

    Output:

    array (
      'Alberto' => 'Alberto',
    )
    ---
    array (
      'Alberto' => 'Bianca',
      'Bianca' => 'Alberto',
    )
    ---
    array (
      'Alberto' => 'Bianca',
      'Bianca' => 'Claudio',
      'Claudio' => 'Alberto',
    )
    ---
    array (
      'Alberto' => 'Claudio',
      'Bianca' => 'Douglas',
      'Claudio' => 'Alberto',
      'Douglas' => 'Bianca',
    )
    ---
    array (
      'Alberto' => 'Claudio',
      'Bianca' => 'Douglas',
      'Claudio' => 'Erica',
      'Douglas' => 'Alberto',
      'Erica' => 'Bianca',
    )
    ---