ValueError: Sample larger than population or is negative
的原因以及解决办法
1.出现
这几天重构kook-valorant-bot
的代码的时候,遇到了这个问题
Job "vip_roll_task (trigger: interval[0:01:20], next run at: 2023-01-25 19:59:21 CST)" raised an exception
Traceback (most recent call last):
File "/home/muxue/.local/lib/python3.10/site-packages/apscheduler/executors/base_py3.py", line 30, in run_coroutine_job
retval = await job.func(*job.args, **job.kwargs)
File "/home/muxue/kook/val-bot/code/main.py", line 793, in vip_roll_task
ran = random.sample(range(0, len(VipRollDcit[msg_id]['user']) - 1), vnum)
File "/usr/local/lib/python3.10/random.py", line 482, in sample
raise ValueError("Sample larger than population or is negative")
ValueError: Sample larger than population or is negative
error raised during task
Traceback (most recent call last):
File "/home/muxue/.local/lib/python3.10/site-packages/apscheduler/executors/base_py3.py", line 30, in run_coroutine_job
retval = await job.func(*job.args, **job.kwargs)
File "/home/muxue/kook/val-bot/code/main.py", line 793, in vip_roll_task
ran = random.sample(range(0, len(VipRollDcit[msg_id]['user']) - 1), vnum)
File "/usr/local/lib/python3.10/random.py", line 482, in sample
raise ValueError("Sample larger than population or is negative")
ValueError: Sample larger than population or is negative
这部分代码是用来生成抽奖结果的随机数的,在网上百度了报错之后,得知是random
生成随机数时产生的报错
2.复现
找到对应的代码
ran = random.sample(range(0, len(VipRollDcit[msg_id]['user'])-1), vnum) # 生成n个随机数
这个代码的作用是,生成vnum
个从0到len(VipRollDcit[msg_id]['user']) - 1
的随机数,不包含len(VipRollDcit[msg_id]['user'])-1
咳咳,这里又发现了另外一个bug:我以为是包含右边界的,所以手动
-1
了;现在导致最后一个参加抽奖的用户永远都抽不到奖了😥正确的range应该是
(0, len(VipRollDcit[msg_id]['user']))
但是,如果参与抽奖的人数少于vnum
,就会出现上面的报错
import random
ran = random.sample(range(0, 2), 3)
可以来简单测试一下,这里我想在0到2之间(其实就是0,1
)生成3个随机数
$ py3 test1.py
Traceback (most recent call last):
File "/home/muxue/kook/test/global_val_test/test1.py", line 16, in <module>
ran = random.sample(range(0, 2), 3)
File "/usr/local/lib/python3.10/random.py", line 482, in sample
raise ValueError("Sample larger than population or is negative")
ValueError: Sample larger than population or is negative
此时运行,就会有这样的报错。
因为这个写法的作用是在0-2
之间产生不重复的随机数,你的目标数量都大于这个集合之中已有数据的数量了,那要怎么生成不重复的随机数呢?
3.解决
解决办法很简单
- 右边界不能等于或者小于左边界
- 产生随机数的数量要小于边界之中数据的数量
比如上面的代码,我们修改一下边界,就能获得正确的结果
import random
ran = random.sample(range(0, 3), 3)
print(ran)
运行
$ py3 test1.py
[0, 2, 1]
对于我的抽奖代码而言,则需要重新操作一番。即可能出现奖品数量大于参与抽奖的人数的情况;
这时候就需要进行判断了
- 奖品数量少于抽奖人数,使用random生成随机数
- 奖品数量大于抽奖人数,抛弃多余奖品,直接生成一个从0到总人数的列表
- 奖品数量等于抽奖人数,上面两种情况都可以用
代码如下
# 人数大于奖品数量
if len(VipRollDcit[msg_id]['user'])>vnum:
ran = random.sample(range(0, len(VipRollDcit[msg_id]['user'])), vnum) # 生成vnum个随机数
else: # 生成一个从0到len-1的列表 如果只有一个用户,生成的是[0]
ran = list(range(len(VipRollDcit[msg_id]['user'])))
这时候就ok了,没有问题了