PHP: Shuffle array, so no value is like the correspondent one

馋奶兔 提交于 2021-01-27 20:05:06

问题


There is an array with names, for example:

$donalds_nephews = array('Huey', 'Dewey', 'Louie');

array
(
    [0] => Huey
    [1] => Dewey
    [2] => Louie
)

I want to shuffle this array, but ensure that no value of the original array has the same key as the shuffled one.

$donalds_nephews_shuffled = shuffle($donalds_nephews);

This could result in 6 possible permutations:

  1. Huey, Dewey, Louie
  2. Huey, Louie, Dewey
  3. Dewey, Louie, Huey
  4. Dewey, Huey, Louie
  5. Louie, Dewey, Huey
  6. Louie, Huey, Dewey

1st, 2nd, 4th and 5th must not be the result.

What's the best way to do so? It's for Secret Santa.


回答1:


Shuffle the original array, then make a copy of it and shift all entries one over, then match the two back together to get your matches.




回答2:


It's for Secret Santa.

Then start with a better algorithm. Currently you seem to be inferring that the key is a present giver and the value a present receiver (or vice versa). This then entails the additional check (and possible re-iteration of the shuffling) to ensure that nobody ends up giving a present to themselves.

But what if you just consider it as an ordered list of names, such that each entry gives to the next person on the list:

$victims=array('Huey', 'Dewey', 'Louie');
shuffle($victims);
$giver='';
foreach($victims as $receiver) {
  if ($giver) print "$giver gives to $receiver\n";
  $giver=$receiver;
}
$receiver=array_shift($victims);
print "$giver gives to $receiver\n";



回答3:


just cause i need this for my secret santa :)

<?php

    function compareArrays($original, $shuffled){   
        for($i = 0; $i < count($original); $i++ ){
            if($original[$i] == $shuffled[$i]){
                return false;
            }
        }
        return true;
    }

    $donalds_nephews = array('Huey', 'Dewey', 'Louie','Igor','Stephan');

    //avoid loops
    for($j = 0; $j < 50; $j++){
        $shuffled = $donalds_nephews;
        shuffle($shuffled);
        $good = compareArrays($donalds_nephews, $shuffled);

        if($good) break;
    }

    if($good){
        echo "here we go!\n";
        foreach($shuffled as $k => $v){
            echo "$k => $v \n";
        }
    }
    else { 
        echo "try again \n";
    }

?>



回答4:


Don't make this complicated by trying to put all of this into one function.

Here's your pseudocode:

$givers  = array( 'Huey', 'Dewey', 'Louie' );
$getters = $givers;

foreach ( $givers as $giver ) {
    do {
        pick a random $getter from $getters;
    } until $getter <> $giver;
    delete $getter from $getters;
    print "$giver gives to $getter\n";
}



回答5:


It is an old question, but you asked for the best way, so how about this?

function santaYates($array) {
    $returnArray = array_values($array); // Cause we need a clean numeric array
    $secure = false;
    for($i = count($returnArray) - 1; $i > 0; $i--) {
        $r = mt_rand(0, $i-1); //subtract 1 from $i to force a new place.
        $tmp = $returnArray[$i];
        $returnArray[$i] = $returnArray[$r];
        $returnArray[$r] = $tmp;
    }

    return $returnArray;
}

It works very similar to the Fisher-Yates shuffle.

There is just one little difference: We permit to use the same key, so every entry will get a new place (cause we substract 1 from $i when we do the randomize step).

Working Demo



来源:https://stackoverflow.com/questions/13849677/php-shuffle-array-so-no-value-is-like-the-correspondent-one

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!