Make writing a habit together! This is the 14th day of my participation in the “Gold Digging Day New Plan · April More Text Challenge”. Click here for more details.

In Python, if we want to modify a set of data while iterating through it, we often have a number of problems. For example, when we do the above operation on a list, we will ignore some data. Data cannot be modified while iterating through the dictionary. In view of these problems, this paper proposes a variety of solutions.

Introduction to the

First, about lists

1. Problem description

In Python, if you try to modify a set of data while iterating through it, this is usually fine. Such as:


l = [3, 4, 56, 7, 10, 9, 6, 5]

for i in l:
    if not i % 2 == 0:
        continue
    l.remove(i)

print(l)
Copy the code

This code iterates through a list of numbers, modifying list L directly to eliminate all even numbers. After running, however, the output is:

[3, 56, 7, 9, 5]
Copy the code

Wait a minute! The output doesn’t seem right. The final result still contains an even number 56. Why didn’t I get rid of this number? We could try printing out all the elements iterated through by the for loop, running the following code:

l = [3, 4, 56, 7, 10, 9, 6, 5]

for i in l:
    print(i)
    if not i % 2 == 0:
        continue
    l.remove(i)

print(l)
Copy the code

The output of this code is:

3, 4, 7, 9, 5Copy the code

As you can see from the output, the for loop does not appear to access all the elements in the list. To see what the for loop does internally, we can use iter and next to simulate it. Take a look at the following example, where I used the ipython shell to run the code:

In [1]: l = [3, 4, 56, 7, 10, 9, 6, 5] In [2]: In [3]: it = iterator In [4]: In [5]: Next (it) Out[5]: 3 In [6]: next(it) Out[6]: 4 In [7]: L.emove (3) In [9]: next(it) Out[9]: 7 In [10]: In [11]: next(it) Out[12]: 9Copy the code

The above experiment reveals that when you remove an element that an iterator has already accessed, the next iteration skips the element on the right and goes directly to the next one.

The reverse is still true, that is, if you add an element to the list at the beginning of the iteration, the next iteration may access the already iterated element, as shown in the following code:

In[1]: l = [3, 4, 56, 7, 10, 9, 6, 5]

In[2]: it = iter(l)

In[3]: next(it)
Out[3]: 3

In[4]: next(it)
Out[4]: 4

In[5]: l.insert(0, 44)

In[6]: next(it)
Out[6]: 4
Copy the code

Notice that when 44 is added to the head of the list, 4 is accessed twice.

2. Solutions

To solve the above problem, we must ensure that we cannot remove elements accessed by the iterator.

Plan a

We can first flip the original list to get a new list, then iterate over the new list and remove the elements from the original list L that do not meet the criteria. The scheme code is as follows:

L = [3, 4, 56, 7, 10, 9, 6, 5] # reversed(l): print(I) if not I % 2 == 0: continue l.remove(i) print(l)Copy the code

The results are as follows:

3. [3, 7, 9, 5]Copy the code

Notice that the iterator now successfully accesses all the elements in the list and finally outputs the list with only odd numbers.

Scheme 2

We can also copy the list L before starting the iteration. However, when there is too much data in list L, this is obviously a performance drain. The scheme code is as follows:

L = [3, 4, 56, 7, 10, 9, 6, 5] # for I in l.opy (): print(I) if not I % 2 == 0: continue l.remove(i) print(l)Copy the code

The output is as follows:

3, 4, 5, 6, 6, 6, 7, 8, 9, 5Copy the code

This scheme ensures that the order of iteration is the same as the order of removal. But because iteration and removal work on two different lists, the same order doesn’t matter.

Ii. About dictionaries

1. Problem description

Dictionaries cannot be modified while iterating over them. As follows:

# {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}
d = {k: k for k in range(10)}

for k, v in d.items():  
    if not v % 2 == 0:    
        continue  
    d.pop(k)
Copy the code

This code generates a RuntimeError:

Traceback (most recent call last):  
  File "F:/Documents/pythonprojects/01practice/app.py", line 7, in <module>  
    for k, v in d.items():
RuntimeError: dictionary changed size during iteration
Copy the code

2. Solutions

We can copy all the keys in the dictionary and then, as we iterate over the keys, remove the elements that don’t meet the criteria. The process is as follows:

# {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9} d = {k: For k in tuple(d.keys()): if not d[k] % 2 == 0: if not d[k] % 2 == 0: continue d.pop(k) print(d)Copy the code

After running the code, the output looks like this:


{1: 1, 3: 3, 5: 5, 7: 7, 9: 9}
Copy the code

We successfully removed all even key-value pairs from the dictionary!

conclusion

In this article, we can’t modify for iteration of a set of data, put forward different solutions: if you want to, when traversing the list to modify the list, we can first to flip or copy of the original list, and get a new list, then in the process of traversing the new list, modify the original data in a list; If we want to modify the dictionary as we walk through it, we can copy all the keys of the dictionary first, and then modify the data in the dictionary as we iterate over the keys.

Thank you

Due to the author’s lack of knowledge, but also time and energy constraints, errors in the code are unavoidable, please readers criticism and correction.

Disclaimer: This article is published for the purpose of passing on more knowledge for exchange and learning. If any source is wrong or violates your legitimate rights and interests, please contact us with proof of ownership, we will correct and delete it in time, thank you.