Posts: 3,458
Threads: 101
Joined: Sep 2016
Apr-24-2017, 04:05 PM
(This post was last modified: Apr-24-2017, 04:05 PM by nilamo.)
Maybe because you're only modifying things you've already iterated over. Regardless, you probably shouldn't do it, and you definitely shouldn't rely on it working right all the time.
In this case, you don't need to (since you only iterate over the list once, and do the same thing with every value in the list regardless of what that value is), and for the same reason, you also don't need a while loop, since it'll only ever run once anyway.
Posts: 566
Threads: 10
Joined: Apr 2017
Apr-24-2017, 06:41 PM
(This post was last modified: Apr-24-2017, 06:41 PM by volcano63.)
(Apr-24-2017, 03:43 AM)nilamo Wrote: Modifying a list while you're in the middle of iterating over that same list is very dangerous. Usually - from the last time I SNAFUed this way (several years ago ) - iterator skips element on each deletion. It's not dangerous - it's a bug
(Apr-23-2017, 10:19 AM)smbx33 Wrote: I made minor modifications to the existing code and provided explanation.
.....
while len(list_) >0: # here you had list[0] I think you wanted to stop when length reached 0
for amount in list_: # for loop will go through the list_ of numbers one amount at a time
.....
list_.remove(amount) #this is to remove items from your list!
# you don't need to check the counter. so the if statement could be deleted or reworded so if the program is run and no items are on the list it says NO ITEMS! else it prints A Though it works - as I have pointed out in previous post, deleting an element of a list while iterating over that list is a bug, which is in this case accidentally compensated for by the external loop. In another scenario, it will not work as expected
This solves the issue
while list_:
s += list_[0]
.....
list_.pop(0) This way you always process first element of the list - while list is not empty, and you don't perform any unnecessary actions
Test everything in a Python shell (iPython, Azure Notebook, etc.) - Someone gave you an advice you liked? Test it - maybe the advice was actually bad.
- Someone gave you an advice you think is bad? Test it before arguing - maybe it was good.
- You posted a claim that something you did not test works? Be prepared to eat your hat.
Posts: 2,955
Threads: 48
Joined: Sep 2016
Iterate over the copy of the list while modifying the original.
for element in list_[:]:
# modify list_
Posts: 3,458
Threads: 101
Joined: Sep 2016
I think the easy solution is to just iterate over a copy of the list, ie: for x in some_list[:]: , but then if the list is large (or is a generator and doesn't exist fully yet), that could just eat memory. Maybe for x in (item for item in some_list): ? That way you can modify the original list, without changing how you iterate. Could make for confusing results sometimes, though.
Posts: 2,955
Threads: 48
Joined: Sep 2016
No problem with the big lists:
for element in iter(list_[:]):
# do something
Posts: 566
Threads: 10
Joined: Apr 2017
Apr-24-2017, 07:02 PM
(This post was last modified: Apr-24-2017, 07:02 PM by volcano63.)
I think a little illustration is in order to show the folly of removing an element from a list while iterating over it.
In [1]: l = list(range(10))
In [2]: for elem in l:
...: l.remove(elem)
...: print(elem)
...:
0
2
4
6
8 And this shows how OP's code worked
In [4]: while l:
...: for elem in l:
...: l.remove(elem)
...: print(elem)
...:
0
2
4
6
8
1
5
9
3
7
Test everything in a Python shell (iPython, Azure Notebook, etc.) - Someone gave you an advice you liked? Test it - maybe the advice was actually bad.
- Someone gave you an advice you think is bad? Test it before arguing - maybe it was good.
- You posted a claim that something you did not test works? Be prepared to eat your hat.
Posts: 331
Threads: 2
Joined: Feb 2017
(Apr-24-2017, 06:41 PM)volcano63 Wrote: (Apr-24-2017, 03:43 AM)nilamo Wrote: Modifying a list while you're in the middle of iterating over that same list is very dangerous. Usually - from the last time I SNAFUed this way (several years ago ) - iterator skips element on each deletion. It's not dangerous - it's a bug
For me it looks like appropriate behaviour - from my understanding list iterator (created with for clause) only keeps information about list object and current index. For i-th loop it gives i-th item from the actual list - and if in i-th loop i-th item is different than i-th item before start of loop, well, its not for/iterator problem, but yours. So if you are removing items from the start of the list while looping over it, it looks like it skips every second item, while if you are removing items from the end of the list, it looks like iteration over first half of the list only. Indeed it makes things rather confusing , so its bettter to avoid it...
(Apr-24-2017, 06:47 PM)nilamo Wrote: I think the easy solution is to just iterate over a copy of the list, ie: for x in some_list[:]: , but then if the list is large (or is a generator and doesn't exist fully yet), that could just eat memory. Maybe for x in (item for item in some_list): ? That way you can modify the original list, without changing how you iterate. Could make for confusing results sometimes, though. Such generator expression would not work, it references original list too, changes would "propagate".
Posts: 566
Threads: 10
Joined: Apr 2017
Apr-24-2017, 08:16 PM
(This post was last modified: Apr-24-2017, 08:17 PM by volcano63.)
(Apr-24-2017, 07:50 PM)zivoni Wrote: (Apr-24-2017, 06:41 PM)volcano63 Wrote: Usually - from the last time I SNAFUed this way (several years ago ) - iterator skips element on each deletion. It's not dangerous - it's a bug
For me it looks like appropriate behaviour - Let me clarify - I was not talking about the interpreter behavior; I was referring specifically to implementation - that using iterator that way is a bug in the implementation. I thought that it was rather obvious
Test everything in a Python shell (iPython, Azure Notebook, etc.) - Someone gave you an advice you liked? Test it - maybe the advice was actually bad.
- Someone gave you an advice you think is bad? Test it before arguing - maybe it was good.
- You posted a claim that something you did not test works? Be prepared to eat your hat.
Posts: 20
Threads: 1
Joined: Apr 2017
Thank you all, I have a deeper understanding of why I was wrong in deleting items off the same list that I am iterating over :P Even though its a bug and gives undesired results(sometimes). Since it was my very first time using remove() as a function, I was very content watching the desired results populate. I now know that if you are removing items from the start of the list while looping over it, it looks like its skips an item, but even if the item is skipped, the while loop will just tell it to iterate again until no items on the list. But that the practice is still confusing and should be avoided.
Posts: 3,458
Threads: 101
Joined: Sep 2016
>>> items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> for ndx, item in enumerate(items):
... print("{0} => {1}".format(ndx, item))
... items.remove(item)
...
0 => 0
1 => 2
2 => 4
3 => 6
4 => 8
5 => 10
>>> items
[1, 3, 5, 7, 9] The for loop keeps track of what index it's at, but when you change the underlying list, the index stays the same... it's just going to refer to a different element. So you don't iterate over the whole list, but it is at least predictable. Predictable, at least, if that's what you were expecting. I still think you either shouldn't modify the list, or use a while loop and only ever use the first element.
|