-1

I encountered something I don't understand. I created a simple example in order to explain it. I have the following list:

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

I iterate through the list, printing the value at the current index, and remove the value if it is even. This results in the next value getting skipped because they all move up one index (filling the gap created by the removal).

for i in numbers:
    print(i)
    if i % 2 == 0:
        numbers.remove(i)

This results in the following output, which is as expected:

1
2
4
6
8
10

When iterating through the list backwards, this problem will be avoided, since all the lower indexes won't be affected by the removal of a higher index.

for i in numbers[::-1]:
    print(i)
    if i % 2 == 0:
        numbers.remove(i)

Which results in (as expected):

10
9
8
7
6
5
4
3
2
1

Now we've arrived at the part I don't understand. As far as I know the default stepsize is 1, so adding [::1] shouldn't make any difference right? Well, it does...

for i in numbers[::1]:
    print(i)
    if i % 2 == 0:
        numbers.remove(i)

Which results in:

1
2
3
4
5
6
7
8
9
10

As yous see all the numbers are getting printed, while I expected some to be skipped due to the shifting explained earlier.

Can someone explain why this is?

Niek
  • 51
  • 8
  • 1
    Because in the third case, you might be removing from the original list but are iterating through a copy of the first list i.e. you are removing from the list `numbers` but on specifying iteration through `numbers[::1]` you basically first create a copy of numbers and then iterate through it. – Anshumaan Mishra Mar 25 '22 at 13:48
  • So using [::1] automatically creates a copy of the original list? – Niek Mar 25 '22 at 13:49
  • Yes, so it is equivalent to `num2 = numbers[::1]`,`for i in num2:` but since `remove` is associated with `numbers`, there is no change in the list being iterated through, sorry for poor english – Anshumaan Mishra Mar 25 '22 at 13:50
  • I think you can add it as an answer. Btw @Niek this code is pretty confusing. If you just want to print even numbers you can do it in 'if'. Can you explain the reason you are using this code. – I-am-developer-9 Mar 25 '22 at 13:54
  • Does this answer your question? [How to remove items from a list while iterating?](https://stackoverflow.com/questions/1207406/how-to-remove-items-from-a-list-while-iterating) – Python learner Mar 25 '22 at 13:58
  • Thanks for all the comments! I understand what happens now. I know this code is a bit confusing (I'm sorry), but it's was just to make clear what I didn't understand. The program where this is a part of tries to iterate through a list of GUIDs, and removes them from the list if there are online on a server. I remove them because I will check again on the remaining after a while. – Niek Mar 25 '22 at 14:16

1 Answers1

3

So, the answer is already there in the comments, just a proper explanation here: Basically, when you say:

for i in numbers:
    print(i)
    if i % 2 == 0:
        numbers.remove(i)

You are iterating through the list numbers
But when you write:

for i in numbers[::1]:
    print(i)
    if i % 2 == 0:
        numbers.remove(i)

It can be seen as an equivalent to:

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]# <-------------
num2 = numbers.copy() #or numbers[::1] <--------------  |
# i.e. python automatically creates a copy of the    |  |
# list numbers to iterate through                    |  |
# since it seems like you are iterating through a    |  | 
# slice of the original list                         |  |
#                                                    |  |
for i in numbers[::1]: # iterates through-------------  |
    print(i)           #                                |
    if i % 2 == 0:     #                                |
        numbers.remove(i) # this removes elements from --

The difference? The copy created is only stored until iteration is done. Hence even when the elements are removed, since the current list is the same, no number is skipped.

Anshumaan Mishra
  • 1,349
  • 1
  • 4
  • 19