第一段引用上面的摘要:
本文旨在解决使用 php Zend 框架编写 Secret Santa 脚本时,当用户数量为奇数时出现的配对问题。我们将分析问题代码,找出导致最后一个用户重复出现的原因,并提供修复方案。此外,还将介绍一种更优雅的实现方式,避免出现“No Pair”的情况,确保所有用户都能参与到 Secret Santa 活动中。
问题分析
原代码在处理奇数用户时,由于递归调用 generateUsers 函数,导致在仅剩一个用户时,仍然会进入 if (count($users) === 1) 的判断分支,从而将该用户与 “No Pair” 重复配对。
解决方案
修改后的 generateUsers 方法,在递归调用之前增加一个判断条件,确保 newUsers 的数量大于 1,避免在只有一个用户时进行递归调用。
function generateUsers(array $defaultUsers, array $updatedUsers = []): bool { $users = (!empty($updatedUsers)) ? $updatedUsers : $defaultUsers; if (count($users) > 1) { if ($this->matchedUsers !== count($this->startingUsers)) { // Pick random user and match with current user. Reset array and repeat until 1 or no users left. $randomUserIndex = rand(1, count($users) - 1); $this->pairs[] = [$users[0], $users[$randomUserIndex]]; unset($users[$randomUserIndex]); unset($users[0]); // Remove pair from list so they can't be assigned again. Reset array for 0 based index $users[0] $newUsers = array_values($users); // Check that there are two or more users if(count($newUsers) > 1){ $this->generateUsers($this->startingUsers, $newUsers); } $this->matchedUsers += 2; } } // If only one user remains can't allocate a Pair if (count($users) === 1) { $orderedUsers = array_values($users); $this->pairs[] = [$orderedUsers[0], "No Pair"]; return true; } return true; }
代码解释:
- 在递归调用 generateUsers 之前,添加了 if(count($newUsers) > 1) 的判断,只有当剩余用户数量大于 1 时,才进行递归调用。这避免了在只有一个用户时重复配对 “No Pair” 的情况。
更优雅的实现方式:循环配对
为了避免出现 “No Pair” 的情况,可以采用循环配对的方式,将所有用户链接成一个环,确保每个人都有礼物可收。
class Match { protected $startingUsers = [ "User1", "User2", "User3", "User4", "User5", ]; protected $pairs = []; function getPairs(): array { $users = $this->startingUsers; shuffle($users); // 打乱用户顺序 for ($i = 0; $i < count($users); $i++) { $giver = $users[$i]; $receiver = $users[($i + 1) % count($users)]; // 使用模运算实现循环 $this->pairs[] = [$giver, $receiver]; } return $this->pairs; } } $match = new Match(); foreach ($match->getPairs() as $pair) { echo "$pair[0] gets $pair[1]"; echo "n"; }
代码解释:
- shuffle($users);: 首先使用 shuffle 函数打乱用户数组的顺序,确保配对的随机性。
- $receiver = $users[($i + 1) % count($users)];: 使用模运算 % 来计算接收者的索引。当 $i 为最后一个用户的索引时,($i + 1) % count($users) 的结果为 0,从而实现最后一个用户与第一个用户配对,形成循环。
优点:
- 避免了 “No Pair” 的情况,确保所有用户都能参与。
- 代码更简洁易懂。
总结
本文针对 PHP Secret Santa 脚本中奇数用户配对问题,提供了两种解决方案。第一种方案通过修改递归调用条件,避免了重复配对 “No Pair” 的情况。第二种方案则采用循环配对的方式,从根本上避免了 “No Pair” 的出现,是一种更优雅的实现方式。开发者可以根据实际需求选择合适的方案。在实际应用中,还可以增加邮件通知等功能,提升用户体验。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END