Python 检查列表中的重复项时循环中断?
我正在尝试使用另一个列表的随机结果生成一个列表,我希望这样做时没有重复项(只有一个例外)。当我检查重复项时,问题就出现了——当它找到一个重复项时,它会自动中断循环,我不知道为什么 据我所知,一切似乎都是正确的。我已经通过pythontutor.com/visualise运行了代码,我尝试了不同的代码片段来检查重复,我已经将循环更改为for循环,while循环,range循环。我测试了我对转折点的定义,我甚至将其复制粘贴到循环中,而不是将其用作函数,我尝试更改“if”语句的位置,等等。我已经做了一整晚了,仍然无法解决问题 编辑:我实际上不希望在某个特定的实例上有这么大的分量(在本例中为“结论”),我只是为了测试重复项检查。实际上,权重更接近于3、1、1、2、1等。 另一件事是,在我的实际代码中,action_表的长度是43个值,而不是7个Python 检查列表中的重复项时循环中断?,python,Python,我正在尝试使用另一个列表的随机结果生成一个列表,我希望这样做时没有重复项(只有一个例外)。当我检查重复项时,问题就出现了——当它找到一个重复项时,它会自动中断循环,我不知道为什么 据我所知,一切似乎都是正确的。我已经通过pythontutor.com/visualise运行了代码,我尝试了不同的代码片段来检查重复,我已经将循环更改为for循环,while循环,range循环。我测试了我对转折点的定义,我甚至将其复制粘贴到循环中,而不是将其用作函数,我尝试更改“if”语句的位置,等等。我已经做了一
#first list to draw random items from
action_table = ["conclusion", "none", "confrontation", "protector", "crescendo", "destroy the thing", "meta"]
#code to draw random items from first list
#first variable weighted to guarantee duplicates for testing
def turning_point():
turning_point = (random.choices(action_table, [500, 1, 1, 1, 1, 1, 1]))
return turning_point
#generate second list called 'plot_points'
plot_points = []
for x in range(int(input("How many Turning Points to generate? "))):
tp = turning_point()
#the code below is what I got from this site
#added tp != to allow duplicates of "none" result
if any(plot_points.count(tp) > 1 for tp in plot_points) and tp != "none":
continue
#results get added to the plot_points list:
plot_points.append(tp)
print(plot_points)
如果删除检查重复项的行,则得到的结果如下:
[['conclusion'], ['conclusion'], ['meta'], ['conclusion'], ['conclusion']]
[['conclusion'], ['conclusion']]
如果我不删除该行,我得到的是:
[['conclusion'], ['conclusion'], ['meta'], ['conclusion'], ['conclusion']]
[['conclusion'], ['conclusion']]
我想要的是:
[['conclusion'], ['none'], ['none'], ['meta'], ['protector']]
错误在这里:
tp != "none"
tp
始终是一个包含一个元素的列表,因为默认情况下random.choices()
返回包含单个元素的列表。从:
random.选择(总体,权重=None,*,累计权重=None,k=1)
返回从包含替换项的总体中选择的k
大小的元素列表
当k
保留为1时,tp
每次都将是一个单元素列表,并且永远不能等于“none”
。它将等于[“无”]
,或[“结论”]
,以此类推。也就是说,`tp!=“无”总是正确的
接下来,您的any()
测试仅在有多个嵌套列表具有当前选定值时生效,因此至少有2个嵌套列表。此时,您将开始跳过出现两次的任何内容,因为tp!=“无”
始终为真:
>>> plot_points = [["conclusion", "conclusion"]]
>>> tp = ["conclusion"]
>>> any(plot_points.count(tp) > 1 for tp in plot_points)
True
>>> tp != "none"
True
您对所给选择的权重使得选择“结论”
之外的任何内容都非常不可能。对于您的7个选项,[“结论”]
将在您调用转折点()函数的506次中选择500次,因此上述场景大部分时间都会出现(每1036579476493次实验中976562500000次将连续出现[“结论”]
5次,或每35次测试中约33次)。因此,您很少会看到任何其他选项被生成两次,更不用说3次了(每64777108次测试中只有3次会将任何其他选项重复三次或更多)
如果您必须生成一个列表,其中除了none
,没有任何内容重复,那么权重选择就没有意义了。一旦选择了“结论”
,您就不能再选择它了。如果目标是使一个“结论”
元素很有可能是结果的一部分,那么只需在最后进行单独的交换,然后首先洗牌剩余选择的列表。洗牌可以将结果缩减为大小,并且第一个N
元素都是随机的、唯一的:
您可以使用“none”
元素填充该列表,使其足够长以满足长度要求,然后根据应包含的可能性在随机位置插入结论:
def plot_points(number):
action_table = ["none", "confrontation", "protector", "crescendo", "destroy the thing", "meta"]
if number > 6:
# add enough `"none"` elements
action_table += ["none"] * (number - 6)
random.shuffle(action_table)
action_table = action_table[:number]
if random.random() > 0.8:
# add in a random "conclusion"
action_table[random.randrange(len(number))] = "conclusion"
return action_table
请注意,这是一个伪加权选择<代码>结论
在80%的时间内被选中,唯一性被保留,只需重复“无”
以填充结果。否则,其他元素就不能具有唯一性
然而,如果你必须
- 输出列表中的唯一值(可能重复
)“无”
- 输入的加权选择
import heapq
import math
import random
def weighted_random_sample(population, weights, k):
"""Chooses k unique random elements from a population sequence.
The probability of items being selected is based on their weight.
Implementation of the algorithm by Pavlos Efraimidis and Paul
Spirakis, "Weighted random sampling with a reservoir" in
Information Processing Letters 2006. Each element i is selected
by assigning ids with the formula R^(1/w_i), with w_i the weight
for that item, and the top k ids are selected.
"""
if not 0 <= k < len(population):
raise ValueError("Sample larger than population or negative")
if len(weights) != len(population):
raise ValueError("The number of weights does not match the population")
key = lambda iw: math.pow(random.random(), 1 / iw[1])
decorated = heapq.nlargest(k, zip(population, weights), key=key)
return [item for item, _ in decorated]
演示:
当然,如果实际的action\u表
要大得多,并且您不允许拾取比操作更多的绘图点,则根本不需要填充内容,您只需直接使用weighted\u random\u sample()
。您好,我建议您对代码进行以下更改:
我尽我最大的努力做尽可能少的改变
def turning_point():
turning_point = (random.choices(action_table))
return turning_point
你的体重太不成比例了,你会多次得到“结论”。
您将注意到两个主要区别:
是否确实要生成包含嵌套单元素列表的列表?为什么不尝试生成<代码>['conclusion','none','none','meta','protector']?我没有意识到random.choices()返回一个列表-我试图返回一个值!我也没有注意到嵌套的1元素列表——我认为它们是单独的值(同样,我对Python是相当陌生的)。这就清楚了-我该如何更改代码,以使_point()只生成值,而不是整个(单个元素)列表?编辑:我这样做的原因是因为我需要对结果进行加权,而我不能对结果进行f
def turning_point():
turning_point = (random.choices(action_table))
return turning_point
for x in range(int(input("How many Turning Points to generate? "))):
tp = turning_point()
print(tp)
#the code below is what I got from this site
#added tp != to allow duplicates of "none" result
plot_points.append(tp)
if any(plot_points.count(tp) > 1 for tp in plot_points) and tp != ["none"]:
plot_points.pop()
#results get added to the plot_points list:
# else:
# plot_points.append(tp)
print(plot_points)
print(plot_points)