问题
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:
- Huey, Dewey, Louie
- Huey, Louie, Dewey
- Dewey, Louie, Huey
- Dewey, Huey, Louie
- Louie, Dewey, Huey
- 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