我正在建立一个礼物交换网站,人们在其中输入电子邮件,然后每个参赛者都与另一个参赛者(发送者)匹配。我正在使用PHP(如果有所作为,可能是Symfony)。
我预计参赛者的数量将在600-800名左右,并且将非常频繁地运行。
我以为我可以在收件人数组上使用shuffle()
和array_combine()
来执行此操作。但是,在shuffle()
之后,发件人可能仍处于同一位置,因此必须给自己一个秘密的圣诞老人礼物。
例如:
$recipients = "SQL query that returns array"
# ['bob', 'alice', 'joe']
$senders = $recipients;
shuffle($senders);
# ['alice', 'bob', 'joe']
$result = array_combine($recipients, $senders);
# ['bob' => 'alice', 'alice' = 'bob', 'joe' => 'joe']
因此,我需要保证在最终数组中,没有任何值等于键。到目前为止,我已经想到了以下可能的解决方案,但它们似乎都很昂贵且有点垃圾:
array_walk()
。将任何值放入另一个数组,然后相互交换。如果只有1,则将其交换任何内容。$recipients
数组中所有具有偶数键的值,以及$senders
数组中所有具有奇数键的值。随机排列这两个数组。shuffle()
实现我自己的cr脚版本,该版本执行的操作类似于将所有值前移两个,然后执行array_reverse()
。array_rand()
从$senders
中选择一项。如果相同,请再次选择,否则将其从阵列中删除,将其设置为该收件人的发件人,然后移至下一个收件人。也许我对此考虑过多-有没有更简单的方法?还是有一种我不知道的在PHP中执行此操作的特殊方法?
combine
$users = array('bob', 'alice', 'joe');
shuffle($users);
$santas = $users;
$santas[] = array_shift($santas);
$result = array_combine($santas, $users);
var_dump($result);
您也可以使用与Fisher-Yates shuffle类似的代码。
function santaYates($array) {
$keys = array_keys($array); //Store the keys
$values = array_values($array); // Cause we need a clean numeric array for this kind of randomisation
$secure = false;
for($i = count($values) - 1; $i > 0; $i--) {
$r = mt_rand(0, $i-1); //subtract 1 from $i to force a new place.
$tmp = $values[$i];
$values[$i] = $values[$r];
$values[$r] = $tmp;
}
$returnArray = array_combine($keys, $values); //Now recombine keys and values
return $returnArray;
}
我为answering a similar question编写了此代码,但是该版本也可以处理关联数组。您可以Test this version