1

Code

def removeEven(List):
    for x in List:
        if x % 2 == 0:
            List.remove(x)
    return List


print(removeEven([18, 106, -158, -124, 199, -28, -68, -91, 46, -190, 63, -30, 142, -36, -162, -121, 14, -192, -143, -57, -59, -129, -146, -76, -186, -84, 70, 19, -13, -12, -5, 179, -191, -43, 160, -156, 105, 104, 93, -188, -184, -197, -136, -35, 16]))

Output

[106, -124, 199, -68, -91, -190, 63, 142, -162, -121, -192, -143, -57, -59, -129, -76, -84, 19, -13, -5, 179, -191, -43, -156, 105, 93, -184, -197, -35]

Code

def removeEven(List):
    result = []
    for x in List:
        if x % 2 != 0:
            result.append(x)
    return result

Output

[199, -91, 63, -121, -143, -57, -59, -129, 19, -13, -5, 179, -191, -43, 105, 93, -197, -35]

I came across this strange behavior. I am writing a simple function to remove even numbers from a list but when I modify the list that is passed as an argument and return it I get a weird output. Does anyone know what the reason is?

Please note i am not looking for answer to this problem it is easy to google but just explanation about why the output is different when i don't create a new list and return it.

Dinero
  • 1,070
  • 2
  • 19
  • 44
  • 3
    You're modifying the list while iterating over it. Create a copy or return a new list with skipped values. `return [x for x in List if x % 2 != 0]` https://stackoverflow.com/a/742383/8014793 – hurlenko Feb 18 '20 at 12:10
  • @hurlenko i know i can use list comprehension but can you explain why i got strange output in the first approach? What is modifying while iterating over it? – Dinero Feb 18 '20 at 12:13
  • It was already answered on SO. I added a link. Basically when you remove an element your list shrinks and current loop iterator will point to the next element. After the iteration ends the pointer will advance one more time skipping one element – hurlenko Feb 18 '20 at 12:13

1 Answers1

1

One Liner in Python using list comprehension:

[x for x in li if x % 2 != 0]

strange output when returning the argument list

You are not permitted to remove elements from the list while iterating over it using a for loop. The best way to do this involves making a new list - either iterate over a copy, or construct a list with only the elements you want and assign it back to the same variable.

As we know, every item in a list lives at its own unique index; which are in order, starting from 0. If we remove an item, any item with an index greater than the one we've removed has now been shifted down.

And here's why that matters:

foo = ['a', 'b', 'c', 'd']
for index in range(len(foo)):
    del foo[index]

In this loop, we're removing all the elements, so we should end up with foo == [], right? This is not the case. In our first trip through the loop, we remove the item at index 0, and the item at index 1 becomes the item at index 0. Our next time through the loop, we remove the item at index 1 which was previously the item at index 2.

See this to learn more on How to remove elements while iterating over a list. See this to learn more on How to remove elements while reverse iterating a list.

abhiarora
  • 9,743
  • 5
  • 32
  • 57
  • Thank you , I know this would work but can you explain why the first approach gave strange output. I am trying to understand why under the hood python does not like me modifying list as i iterate – Dinero Feb 18 '20 at 12:14
  • See my edited answer. – abhiarora Feb 18 '20 at 12:19