I'm not allowed to use the .remove() function to delete even numbers in a list and the specs say: You will be modifying the original list, so its id() must not change.This is what I have:
def remove_evens(xs):
for i in range(len(xs)):
for x in xs:
if x%2==0:
del xs[i]
return xs
If for instance I test the function and I input xs=[1,2,3,4,5] it returns [3,5]. I don't know why the 1 doesn't return
That's because you're iterating over the list and modifying it at the same time. This means the index i isn't always correct because you've just removed an element from the list. This leads to skipping elements and that's why the 1 isn't in there.
You can do:
def remove_evens(xs):
return [x for x in xs if x % 2 != 0]
This uses a list comprehension to create a list without the even numbers. If you need to modify the existing list you can do:
def remove_evens(xs):
to_remove = []
for i, x in enumerate(xs):
if x % 2 == 0:
to_remove.append(i)
for j in to_remove:
del xs[j]
return xs
This creates a list to_remove which keeps track of the positions of the elements that need to be removed.
Maybe something like this will work for you.
>>> xs = [1,5,123,6,2,34]
>>> id(xs)
35519496L
>>> lastidx = len(xs) - 1
>>> for i, x in enumerate(reversed(xs)):
... if x%2==0:
... del xs[lastidx-i]
...
>>> xs
[1, 5, 123]
>>> id(xs)
35519496L
It's linear time because it iterates over the list only once. When you iterate over a list backwards, you can freely delete elements without modifying the indexes of future elements that you haven't looped over yet. Also the id of the list does not change with this method, as you can see. :)
Here is another way to do the same thing with only range/xrange and len.
>>> xs = [1,5,123,6,2,34]
>>> for i in range(len(xs)-1,-1,-1):
... if xs[i]%2==0:
... del xs[i]
...
>>> xs
[1, 5, 123]
Both ways do the same thing so whichever way you decide to use is a matter of preference/personal style.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With