【问题标题】:Weird 'partial completion' of loop奇怪的“部分完成”循环
【发布时间】:2015-05-06 02:10:45
【问题描述】:

好吧,这可能真的很微不足道(我对此很陌生),但我已经坚持了一段时间,我不明白为什么下面的函数会返回如此奇怪的结果。

testx = [(1,2), (1,1), (2,2), (3,5), (4,4), (5,5)]

def test_loop(interval_set):
for item in interval_set:
    if item[0] == item[1]:
        interval_set.remove(item)
return interval_set

print test_loop(testx)

>>>[(1, 2), (2, 2), (3, 5), (5, 5)]

如果您注意到,只有重复集 (1,1) 和 (4,4) 被删除,而 (2,2) 和 (5,5) 保留在列表中。这几乎是不合逻辑的,请协助。

【问题讨论】:

标签: python loops for-loop


【解决方案1】:

迭代集合(字典、列表、集合)同时从中删除内容是不好的,因为您将删除项目、缩短集合并提前退出循环。

我建议做一个列表理解,像这样:

[item for item in testx if item[0] != item[1]]

获得你期望的结果。

您可以在此处阅读有关列表理解的文档https://docs.python.org/2/tutorial/datastructures.html#list-comprehensions

【讨论】:

    【解决方案2】:

    在迭代同一个列表时,不应从列表中删除项目。尝试遍历该列表的副本,如下所示:

    testx = [(1,2), (1,1), (2,2), (3,5), (4,4), (5,5)]
    
    def test_loop(interval_set):
        for item in list(interval_set):
            if item[0] == item[1]:
                interval_set.remove(item)
        return interval_set
    
    print test_loop(testx)
    

    输出:

    [(1, 2), (3, 5)]
    

    【讨论】:

    • 建立一个新的值列表来保留,而不是制作一个副本进行迭代,以便您可以从原始文件中删除,通常更简单。特别是对于列表,因为否则您必须向后做事。 (对于集合,这不是问题那么多,因为您可以使用remove,但这仍然不是最好的处理方式。)
    • @abarnert 对。我也更喜欢做一个列表理解。只是想向 OP 展示他如何最小限度地更改代码并使其正常工作。
    • 天哪,谢谢。我不敢相信一个添加 list() 设法改变了结果。不知道我理解为什么 python 不能直接迭代,但现在知道如何避免它!谢谢!
    • @VickneshKodakManoselvam:了解添加 list() 的作用(它会复制列表)以及为什么会有所作为非常重要(在这个答案和另一个答案中对此进行了解释) ,并且可能在 NPE 给您的链接中,所以希望如果您阅读所有这些链接,您可以理解它。
    • @VickneshKodakManoselvam 嘿,我仍然建议阅读有关列表推导的内容,这是实现您所尝试的更 Pythonic 的方式。
    【解决方案3】:

    只是添加一些说明,说明为什么修改您正在迭代的序列是一个坏主意。这是一个列表,箭头表示迭代器当前所在的位置:

     v
    [0, 1, 2, 3, 4, 5]
    

    现在假设您删除了0,发生的情况是列表向前移动,所以现在看起来像这样,注意迭代器的位置:

     v
    [1, 2, 3, 4, 5]
    

    现在迭代器前进到下一个项目而无需评估/比较/无论1

        v
    [1, 2, 3, 4, 5]
    

    现在您的代码已备份到 for 循环的第一行,它将在值 2 上执行您的代码,但从未评估过 1

    使用列表推导通常是最好的方法,但有时由于推导语法的限制,需要一个单独的函数。

    def test_loop(interval_set):
        return [item for item in interval_set if item[0] != item[1]]
    

    如果您在数学意义上构建set(没有重复),也可以作为未来的提示:

    >>> interval_set = [(1,1), (1,1), (2,2), (3,5), (4,4), (4,4)]
    >>> set(interval_set)
    set([(1,1), (2,2), (3,5),(4,4)])
    

    【讨论】:

    • 天啊,真是一个了不起的解释!我明白了,谢谢!
    猜你喜欢
    • 2018-11-07
    • 1970-01-01
    • 2020-04-21
    • 1970-01-01
    • 2019-08-05
    • 2017-08-20
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    相关资源
    最近更新 更多