13

Why does my code not remove the last empty element in the list?

templist = ['', 'hello', '', 'hi', 'mkay', '', '']

for element in templist:
    if element == '':
        templist.remove(element)

print (templist)

Output:

['hello', 'hi', 'mkay', '']
Clone
  • 3,378
  • 11
  • 25
  • 41
  • 2
    `templist = [x for x in templist if x != '']` or `templist = list(filter(None, templist))`. Assign to `templist[:]` if you want to mutate the original list. – Steven Rumbalski Nov 14 '16 at 21:45
  • 1
    Question was marked as duplicated, but you can find my answer (with explanations why your code doesn't work) here: https://gist.github.com/ischurov/028f2636c97f1e1a83f04ff10332a04d – Ilya V. Schurov Nov 14 '16 at 21:56

4 Answers4

30

Well, you could always just do this:

new_list = list(filter(None, templist))
P.hunter
  • 1,345
  • 2
  • 21
  • 45
Elliot Roberts
  • 910
  • 5
  • 10
12

Because you are mutating the list that is being iterating over. Think of it as if the for loop is iterating using an index; removing elements reduces the length of the list thereby invalidating indices > len(list) - 1.

The "Pythonic" solution to this is to use a list comprehension:

templist = ['', 'hello', '', 'hi', 'mkay', '', '']
templist[:] = [item for item in templist if item != '']

This performs in place removal of items from the list.

mhawke
  • 84,695
  • 9
  • 117
  • 138
  • 3
    A) this is a dup. B) `[item for item in templist if item]` is sufficient. Empty strings evaluate to false. – TemporalWolf Nov 14 '16 at 21:47
  • 3
    @TemporalWolf: A) a dup of what? B) I didn't want to make the assumption that items such as `None`, 0, and other items that evaluate to `False` should be removed. The OP states "empty element" - `0` and `None` are not _empty_. – mhawke Nov 14 '16 at 21:50
  • 1
    @TemporalWolf: oh I see, the question is a dup, not this answer. This answer is different to that accepted in that question (it mentions in place replacement), and, although the concept is the same, this question pertains to empty strings, not empty lists. – mhawke Nov 14 '16 at 21:55
  • There are other more "accurate" [questions](http://stackoverflow.com/questions/16099694/how-to-remove-empty-string-in-a-list), but they have worse quality answers. Still very, very duplicate. – TemporalWolf Nov 14 '16 at 21:59
  • 2
    @TemporalWolf: OP asks _why_ their code does not work. The other question simply asks how to remove items from a list. There is a fundamental difference so, not "very, very duplicate" at all. None of the answers in that question address the reason. This is a better example of a duplicate question: http://stackoverflow.com/questions/2896752/removing-item-from-list-during-iteration-whats-wrong-with-this-idiom – mhawke Nov 14 '16 at 22:05
  • **If whitespace should count as empty too**, such as `" "`, add an `and not item.isspace()` after `item != ''`. `str.isspace()` returns `True` when the string consists only of whitespace (blank characters), but not when the string is completely empty. – j307 Apr 24 '23 at 12:23
6

To point out your error, by iterating through a copy of the list, i.e changing your for statement to:

for element in templist[:]:

Altering a list while you iterate over it leads to the odd results you see.

More compactly, you could use filter for this:

templist = list(filter(None, templist))

when None is supplied to it, it simply returns elements that are true (empty strings evaluate to false).

Dimitris Fasarakis Hilliard
  • 150,925
  • 31
  • 268
  • 253
2

You could make a new list called wordGrabber for example and instead of removing the blanks you could populate your new list with content

templist = ['', 'hello', '', 'hi', 'mkay', '', '']

for element in templist:
    if element != '':
        wordGrabber.append(element)

print (wordGrabber)
Steven Rumbalski
  • 44,786
  • 9
  • 89
  • 119
  • 1
    Please review [how to format code](http://meta.stackexchange.com/questions/22186/how-do-i-format-my-code-blocks) in your answers. I have edited your answer so that the code is formatted. – Steven Rumbalski Nov 14 '16 at 21:50