对于带有嵌套列表的字典,删除不起作用

Remove does not work as intended for dictionary with nested list

我有这本带有 key, value 对的字典,其中 value 是一个嵌套列表。根据条件,如果在 value 对象的列表中找不到 key,我想 remove 它。

我所做的是:

for key, value in example.items():
    for val in value:
        if key not in val:
            value.remove(val)

我不明白的是,为什么这对第一对 key, val 有效但对第二对无效?如下...

example = {"a": [["a", "b", "c", "d"],
                 ["e", "f", "g", "h"],
                 ["a", "i", "j", "k"],
                 ["f", "y", "a", "q"],
                 ["a", "b", "c", "d"],
                 ["e", "f", "b", "h"],
                 ["a", "i", "j", "k"],
                 ["o", "p", "a", "l"]],
           "b": [["a", "b", "c", "d"],
                 ["e", "f", "b", "h"],
                 ["a", "i", "j", "k"],
                 ["o", "p", "a", "l"],
                 ["a", "b", "c", "d"],
                 ["e", "f", "g", "h"],
                 ["a", "i", "j", "k"],
                 ["f", "y", "a", "q"]]}

使用输出上方的代码块是:

{'a': [['a', 'b', 'c', 'd'], ['a', 'i', 'j', 'k'], ['f', 'y', 'a', 'q'], ['a', 'b', 'c', 'd'], ['a', 'i', 'j', 'k'], ['o', 'p', 'a', 'l']], 'b': [['a', 'b', 'c', 'd'], ['e', 'f', 'b', 'h'], ['o', 'p', 'a', 'l'], ['a', 'b', 'c', 'd'], ['a', 'i', 'j', 'k']]}

我遇到过这个衬里,它似乎工作正常(假设指定元素的索引是一致的)-

for k,v in my_dict.items():
    my_dict[k] = list(filter(lambda x: x[0] == k, v))

但为什么 remove 不能按上述示例的预期工作?

实际上,它甚至对第一个元素也不起作用。核心问题是你改变了你正在迭代的列表,特别是这个:

    for val in value:
        if key not in val:
            value.remove(val)

这里发生的是,在内部,迭代器是使用索引实现的。其含义显示如下示例:

In [36]: lst = [0,1,2,3]                                                                                                                                                                                                                                                       

In [37]: for item in lst: 
    ...:     lst.remove(item) 
    ...:                                                                                                                                                                                                                                                                       

In [38]: lst                                                                                                                                                                                                                                                                   
Out[38]: [1, 3]

请注意,在第一次迭代中,您正在处理第 0 个元素,并删除该元素。在此迭代结束时,内部索引增加到 1。但是,通过删除第 0 个元素,整个列表会移动,因此您实际上跳过了现在位于第 0 个位置的元素“1”。类似的事情再次发生,跳过“3”。

请注意,这是标准 python 实现的行为(通常我 认为 该行为未定义。

在您的情况下发生的情况是,在第一种情况下,不会评估在删除的元素之后紧随其后的所有元素(如上面的虚拟情况)。 'a''b' 列表之间的唯一区别是,在 'a' 列表的情况下,恰好紧随删除列表之后的所有列表无论如何都包含 'a' 所以你不想要它们已删除(即,您在评估期间跳过它们并不重要。

解决此问题的简单方法是创建您正在迭代的列表的副本:

    for val in list(value):
        if key not in val:
            value.remove(val)