views:

327

answers:

5

I want to remove all empty strings from a list of strings in python.

My idea looks like this:

while '' in str_list:
    str_list.remove('')

Is there any more pythonic way to do this?

+11  A: 

I guess list comprehensions

list = ["first", "", "second"]
[x for x in list if x]

Output: ['first', 'second']

Edit: Shortened as suggested

Ib33X
I'd probably just shorten this a bit to [x for x in list if x]
Randle Taylor
A: 

Loop through the existing string list and then check for a empty string, if it's not empty populate a new string list with the non-empty values and then replace the old string list with the new string list

Roland
+13  A: 

I would use filter:

str_list = filter(None, str_list) # fastest
str_list = filter(bool, str_list) # fastest
str_list = filter(len, str_list)  # a bit of slower
str_list = filter(lambda item: item, str_list) # slower than list comprehension

Tests:

>>> timeit('filter(None, str_list)', 'str_list=["a"]*1000', number=100000)
2.4797441959381104
>>> timeit('filter(bool, str_list)', 'str_list=["a"]*1000', number=100000)
2.4788150787353516
>>> timeit('filter(len, str_list)', 'str_list=["a"]*1000', number=100000)
5.2126238346099854
>>> timeit('[x for x in str_list if x]', 'str_list=["a"]*1000', number=100000)
13.354584932327271
>>> timeit('filter(lambda item: item, str_list)', 'str_list=["a"]*1000', number=100000)
17.427681922912598
livibetter
or `filter(len, str_list)`
Nick D
@Nick, I thought too much. How about using `bool`? I did a quick test, it's faster than `len`.
livibetter
@livibetter, oh yeah! Why not edit your answer to include it?
Nick D
How about `filter(None, str_list)` `real 0m0.390s ``user 0m0.332s ``sys 0m0.056s `
Tumbleweed
@Tumbleweed, using None (meaning using identity function according to doc) or bool seem to have same performance.
livibetter
may be, but timeit shows the difference, and use of None is more readble and clear - as per my opinion ! or I would like to say use of filter(None, l1) will look more pythonic way
Tumbleweed
`filter(bool, ...)` looks like a nice pattern, +1
TokenMacGuy
+1  A: 

Depending on the size of your list, it may be most efficient if you use list.remove() rather than create a new list:

l = ["1", "", "3", ""]

while True:
  try:
    l.remove("")
  except ValueError:
    break

This has the advantage of not creating a new list, but the disadvantage of having to search from the beginning each time, although unlike using while '' in l as proposed above, it only requires searching once per occurrence of '' (there is certainly a way to keep the best of both methods, but it is more complicated).

Andrew Jaffe
+3  A: 

filter actually has a special option for this:

filter(None, sequence)

It will filter out all elements that evaluate to False. No need to use an actual callable here such as bool, len and so on.

It's equally fast as map(bool, ...)

Ivo van der Wijk