#5 老张 这两段代码都是用于从一个抽奖活动(lottery
)中选出中奖者的过程,但其实现方式有所不同。
原算法
$winners = $lottery->participants()
->inRandomOrder()
->limit($lottery->amount)
->get();
$winnerIds = $winners->pluck('id');
$lottery->participants()->whereIn('id', $winnerIds)->update(['status' => 1]);
含义:
- 获取参与者:从
$lottery
对象中获取所有参与者。
- 随机排序:使用
inRandomOrder()
方法随机打乱参与者的顺序。
- 限制数量:使用
limit($lottery->amount)
限制获取的参与者数量为抽奖数量(amount
)。
- 获取中奖者:通过
get()
方法获取幸运中奖者的信息。
- 提取ID:使用
pluck('id')
提取中奖者的ID,以便后续操作。
- 更新状态:将选出的中奖者的状态更新为1,表示该参与者已中奖。
新算法
$seed = crc32($lottery->id . $lottery->created_at);
srand($seed); // 使用种子初始化随机数生成器
$participantIds = $lottery->participants()->pluck('id')->toArray();
shuffle($participantIds); // 打乱顺序
$winnerIds = array_slice($participantIds, 0, $lottery->amount);
// 根据 winnerIds 查询中奖者
$winners = $lottery->participants()->whereIn('id', $winnerIds)->get();
$lottery->participants()->whereIn('id', $winnerIds)->update(['status' => 1]);
含义:
- 生成种子:通过
crc32
对抽奖活动的ID和创建时间进行哈希,生成一个整型种子。
- 初始化随机数生成器:使用
srand($seed)
初始化随机数生成器,使其可重复性。
- 获取参与者ID:提取所有参与者的ID,转换为数组。
- 打乱顺序:使用
shuffle($participantIds)
对参与者ID数组进行随机打乱。
- 选择中奖者:使用
array_slice($participantIds, 0, $lottery->amount)
从打乱后的ID数组中选择前N个(amount
)作为中奖者。
- 查询中奖者信息:根据
winnerIds
去数据库中查询中奖者的详细信息。
- 更新状态:将中奖者的状态更新为1,表示该参与者已中奖。
总结
- 原算法通过数据库的随机排序功能直接从参与者中获取中奖者,效率较高。
- 新算法通过手动生成随机数种子并打乱参与者ID的方式,提供了一种可重复的抽奖方式,确保在相同的条件下能够得到相同的结果。
- 新算法的可控性较好,但在参与者数量比较大的情况下,可能性能略逊于原算法。