对于带有嵌套列表的字典,删除不起作用
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)
我有这本带有 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)