Python 检查列表中的重复项时循环中断?

Python 检查列表中的重复项时循环中断?,python,Python,我正在尝试使用另一个列表的随机结果生成一个列表,我希望这样做时没有重复项(只有一个例外)。当我检查重复项时,问题就出现了——当它找到一个重复项时,它会自动中断循环,我不知道为什么 据我所知,一切似乎都是正确的。我已经通过pythontutor.com/visualise运行了代码,我尝试了不同的代码片段来检查重复,我已经将循环更改为for循环,while循环,range循环。我测试了我对转折点的定义,我甚至将其复制粘贴到循环中,而不是将其用作函数,我尝试更改“if”语句的位置,等等。我已经做了一

我正在尝试使用另一个列表的随机结果生成一个列表,我希望这样做时没有重复项(只有一个例外)。当我检查重复项时,问题就出现了——当它找到一个重复项时,它会自动中断循环,我不知道为什么

据我所知,一切似乎都是正确的。我已经通过pythontutor.com/visualise运行了代码,我尝试了不同的代码片段来检查重复,我已经将循环更改为for循环,while循环,range循环。我测试了我对转折点的定义,我甚至将其复制粘贴到循环中,而不是将其用作函数,我尝试更改“if”语句的位置,等等。我已经做了一整晚了,仍然无法解决问题

编辑:我实际上不希望在某个特定的实例上有这么大的分量(在本例中为“结论”),我只是为了测试重复项检查。实际上,权重更接近于3、1、1、2、1等。 另一件事是,在我的实际代码中,action_表的长度是43个值,而不是7个


#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%的时间内被选中,唯一性被保留,只需重复
“无”
以填充结果。否则,其他元素就不能具有唯一性

然而,如果你必须

  • 输出列表中的唯一值(可能重复
    “无”
  • 输入的加权选择
那你就要一个。您可以使用标准Python库实现这一点:

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
你的体重太不成比例了,你会多次得到“结论”。 您将注意到两个主要区别:
  • 我更改了添加到列表的位置,并用一个pop()函数替换了continue语句。问题是,您检查“计数”太晚了(例如,您的循环会在绘图点中插入“结论”inoto,然后end和tp会更改值,比如在检查any..时更改为“保护器”)。因此,追加,然后检查计数,然后弹出,如果你有太多对我更有意义
  • 我改变了你的tp!=“无”到tp!=[“无”],因为请记住,您使用的是单一成员列表
  • 我添加了一些打印语句,这样您就可以直观地看到每次迭代中发生的事情

  • 是否确实要生成包含嵌套单元素列表的列表?为什么不尝试生成<代码>['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)