Python读取Excel时如何避免随机函数重复选取同一行
解决随机选取Excel行重复的问题
问题根源
你当前用random.randint(2, length_row)每次随机生成行号,但没有跟踪已选过的行,所以会出现重复选取的情况。下面给你两种实用的解决方案,附带详细解释。
方案1:生成候选行列表并打乱(推荐)
这种方法先把所有可选的行号整理成列表,打乱顺序后依次取用,从根本上避免重复,效率也更高,尤其适合要选的题目数量较多的场景。
修改后的代码:
import random # 必须导入random库,原代码遗漏了这一步 from openpyxl import Workbook, load_workbook # 建议把导入语句放在代码开头,更规范高效 if (1 <= numb_quiz <= 100): book = load_workbook('Quiz_Problems.xlsx') read_sheet = book['100 Questions'] length_row = read_sheet.max_row sheet = book.active numb_question = 1 point = 0 engagement = 0 correct = 0 # 生成所有可选行号的列表(从第2行到最后一行) available_rows = list(range(2, length_row + 1)) # 打乱列表顺序,实现随机排序 random.shuffle(available_rows) # 遍历打乱后的列表,取前numb_quiz个行号作为题目 for randrow in available_rows[:numb_quiz]: print("") print("Question number", str(numb_question) + ":") # 读取第2列的题目内容 for row in read_sheet.iter_rows(randrow, randrow, min_col=2, max_col=2): print([cell.value for cell in row]) # 读取第3列的选项内容 for col in read_sheet.iter_rows(min_row=randrow, max_row=randrow, min_col=3, max_col=3): print([cell.value for cell in col]) break guest_answer = str(input("answer: ")) answer = str("D"+str(randrow)) correct_ans = sheet[answer].value numb_question += 1 # 别忘了递增题目编号
关键部分解释:
available_rows = list(range(2, length_row + 1)):生成从第2行到Excel最后一行的所有行号列表,确保覆盖所有可用题目。random.shuffle(available_rows):原地打乱列表顺序,不需要额外变量接收返回值,直接修改原列表,实现随机排序。available_rows[:numb_quiz]:取打乱后列表的前numb_quiz个元素,刚好是你需要的题目数量,且完全不会重复。
方案2:记录已选行号,重复则重新随机
这种方法适合可选题目数量远大于要选数量的场景(比如选5题但有100题),通过集合记录已选行号,每次随机后检查是否重复。
修改后的代码:
import random from openpyxl import Workbook, load_workbook if (1 <= numb_quiz <= 100): book = load_workbook('Quiz_Problems.xlsx') read_sheet = book['100 Questions'] length_row = read_sheet.max_row sheet = book.active numb_question = 1 point = 0 engagement = 0 correct = 0 selected_rows = set() # 用集合存储已选行号,集合查询速度远快于列表 while numb_question <= numb_quiz: randrow = random.randint(2, length_row) if randrow in selected_rows: continue # 如果已经选过,跳过当前循环,重新生成随机行号 selected_rows.add(randrow) # 没选过就加入集合,标记为已选 print("") print("Question number", str(numb_question) + ":") for row in read_sheet.iter_rows(randrow, randrow, min_col=2, max_col=2): print([cell.value for cell in row]) for col in read_sheet.iter_rows(min_row=randrow, max_row=randrow, min_col=3, max_col=3): print([cell.value for cell in col]) break guest_answer = str(input("answer: ")) answer = str("D"+str(randrow)) correct_ans = sheet[answer].value numb_question += 1
关键部分解释:
selected_rows = set():使用集合存储已选行号,因为集合的成员查询操作(randrow in selected_rows)是O(1)时间复杂度,比列表快很多,避免频繁重复检查拖慢程序。if randrow in selected_rows: continue:如果生成的行号已经被选过,直接跳过当前循环,重新生成随机数,直到拿到未选过的行号。
两种方案对比
- 方案1:一次性生成所有随机行号,逻辑清晰,不会出现重复,适合要选的题目数量接近总题目数的场景(比如选90题但只有100题),不会出现无限循环的风险。
- 方案2:每次随机后检查,适合要选的题目数量远小于总题目数的场景,代码改动相对小,但如果要选的数量接近总数,可能会频繁重复生成随机数,效率较低。
另外注意:你的原代码没有导入random库,运行时会报错,一定要在代码开头加上import random!
内容的提问来源于stack exchange,提问作者bin07
相关产品推荐
相关产品推荐

