Python Remove Element In For Loop
Solution 1:
numbers_buf = numbers[:] # make a copy not a referencedefpurify(numbers):
numbers_buf = numbers[:]
for item in numbers:
if item % 2:
numbers_buf.remove(item)
return numbers_buf
manipulating/removing elements while you iterate over a list will change the index of elements, numbers_buf = numbers
creates a reference to the numbers
list, basically a pointer to the same object so remove from one, remove from both.
Using numbers[:]
creates a copy/new object.
Run the following function to help make it clear, see how 3 and 4 somehow did a runner:
def purify(numbers):
numbers_buf = numbers
should_be = numbers[:]
for ind, item in enumerate(numbers):
print("{} should be at {}, is at {}".format(item,should_be.index(item),ind))
if item % 2:
numbers_buf.remove(item)
return numbers_buf
print(purify([4,5,4,7,3,1]))
if you did want to use a list comp to modify the original object:
def purify(numbers):
numbers[:] = [x for x in numbers ifnot x % 2]
return numbers
You can also use reversed
:
defpurify(numbers):
for item inreversed(numbers):
if item % 2:
numbers.remove(item)
return numbers
Solution 2:
This has been asked many times, look at Modifying list while iterating
You should really be doing:
even = [a for a in numbers if a%2 == 0]
Solution 3:
You are doing two things that you probably should not, as both of them are asking for trouble.
Never, ever, ever add to or remove items from an array while you're iterating over it. This will confuse both Python and you and almost certainly not achieve the desired result.
You really shouldn't be modifying the array in place anyway. The function doesn't get a copy of the array; it's modifying the actual array passed in by the caller. This is likely to be surprising behavior to everyone involved:
a = [1,2,3,4] print purify(a) #=> [2, 4]print a #=> [2, 4]
You should construct and return a new array instead, and perhaps change the function name to indicate that (similar to the sort
and sorted
built-ins):
defpurified(a):
return [n for n in a if n % 2 == 0]
a = [1,2,3,4]
print purified(a) #=> [2, 4]print a #=> [1, 2, 3, 4]
Solution 4:
Your problem stems from the fact that you are not looping over a different list, like you want to be. You want to avoid deleting something from a list while looping over it, which is why you created a new list with numbers_buf = numbers
However, note that no new list was created:
In [73]: numbers = list(range(10))
In [74]: numbers
Out[74]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [75]: id(numbers)
Out[75]: 4469310792
In [76]: numbers_buf = numbers
In [77]: id(numbers)
Out[77]: 4469310792
In [78]: id(numbers_buf)
Out[78]: 4469310792
In [79]: id(numbers_buf) == id(numbers)
Out[79]: True
In [80]: numbers
Out[80]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [81]: numbers_buf
Out[81]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [82]: numbers.append(10)
In [83]: numbers_buf
Out[83]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Notice in the end, when I append 10
to numbers
, it gets appended to numbers_buf
as well. This is because python doesn't create a new list with numbers in them when you do numbers_buf = numbers
; It simply creates the name numbers_buf
and makes it point to the exact same structure that numbers
points to (this is what all that id(numbers)
stuff shows). You could solve this problem as follows:
In [84]: numbers_buf_new = numbers[:]
In [85]: id(numbers_buf_new)
Out[85]: 4469329032In [86]: id(numbers_buf_new) == id(numbers)
Out[86]: FalseIn [87]: numbers
Out[87]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
In [88]: numbers_buf_new
Out[88]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
In [89]: numbers.append(11)
In [90]: numbers
Out[90]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
In [91]: numbers_buf_new
Out[91]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Solution 5:
If you want to retain using remove method and return the same list, you can try this:
defpurify(numbers):
for item in numbers:
if item % 2 == 1:
count = numbers.count(item)
for i inrange(count):
numbers.remove(item)
return numbers
Post a Comment for "Python Remove Element In For Loop"