首页 > 解决方案 > Iterate data structure while it is updated

问题描述

What is the correct way to iterate over a data structure in python while elements are removed from the structure at the same time?

I want to iterate over the someList structure and make sure to reach all items in the list as long as they are in the list and remove some of the items while I iterate it. But I don't understand why some numbers are skipped and how I can avoid this, resp. make sure to actually see each element in the list exactly once, under the condition, that it was not removed in advance. In the example I never saw 1, 5, and 8

class someList():
    def __init__(self):
        self.list = list(range(0,10))

    def getData(self):
        for i in self.list:
            print(i)
            yield i

thing = someList()
for a in thing.getData():
    print("we reached:", a)
    if a % 2 == 1:
        print("remove", a)
        thing.list.remove(a)
    elif (a * 2) in thing.list:
        print("remove double a:", a, " a*2:", a * 2)
        thing.list.remove(a*2)
print(thing.list)

Output:

0
we reached: 0
remove double a: 0  a*2: 0
2
we reached: 2
remove double a: 2  a*2: 4
3
we reached: 3
remove 3
6
we reached: 6
7
we reached: 7
remove 7
9
we reached: 9
remove 9
[1, 2, 5, 6, 8]

Intended Output:

0
we reached: 0
remove double a: 0  a*2: 0
1
we reached: 1
remove 1
2
we reached: 2
remove double a: 2  a*2: 4
3
we reached: 3
remove 3
5
we reached: 5
remove 5
6
we reached: 6
7
we reached: 7
remove 7
8
we reached: 8
9
we reached: 9
remove 9
[2, 6, 8]

Note: this is not the same question as How to remove items from a list while iterating? because I do not want to filter out the elements before I iterate.

The two modifying conditions are just examples as I indeed do iterate over a graph data structure, consume the current element and remove some elements that have a specific relation to the current element.

标签: pythonyield

解决方案


正如其他人所说,如果您尝试在运行时修改列表,您将无法获得正确的迭代,因此请使用另一个列表来存储您要删除的内容,

class someList():
    def __init__(self):
        self.list = list(range(0,10))

    def getData(self):
        for i in self.list:
            print(i)
            yield i

thing = someList()
rem_list=[]
for a in thing.getData():
    print("we reached:", a)
    if a in rem_list:
        pass
    elif a % 2 == 1:
        print("remove", a)
        rem_list.append(a)
    elif (a * 2) in thing.list:
        print("remove double a:", a, " a*2:", a * 2)
        rem_list.append(2*a)
thing.list=[x for x in thing.list if x not in rem_list]
print(thing.list) #outputs [2, 6, 8]

使用 rem_list 存储要删除的成员而不是循环检查它们会给你预期的结果..


推荐阅读