Reputation: 15680
this has been irking me for years.
given I have a list of words :
words = [ 'one', 'two', 'three', '', ' four', 'five ', 'six', \
'seven', 'eight ', ' nine', 'ten', '']
even though it's super lightweight, I still feel weird writing this list comprehension:
cleaned = [ i.strip() for i in words if i.strip() ]
i don't like applying strip() twice. it just seems silly.
it's slightly/negligibly faster like this:
_words = [ w.strip() for w in words ]
cleaned = [ w for w in _words if w ]
which is also the same as
cleaned = [ i for i in [ w.strip() for w in words ] if i ]
I'm wondering if there are other ways to write this.
I was largely interested in a nested loops form of list comprehensions ( see Idiom for flattening a shallow nested list: how does it work? ) , but I couldn't figure anything out.
I put benchmark up on github, outlining my original 3 approaches, and ones shared below.
The fastest is @Martijn Pieters filter()
; converting the inner list to a generator expression is a negligible hit to speed, but should be better for memory management (according to python's docs ).
All the speed differences involved are , expectedly, negligible and not worth sharing.
Upvotes: 5
Views: 140
Reputation: 24153
I have a slight variation, where I create a single valued temporary list:
>>> cleaned = [stripped for word in words
... for stripped in [word.strip()]
... if stripped]
More generally:
>>> values = [transformed for value in sequence
for transformed in [transform(value)]
if want(transformed)]
Upvotes: 1
Reputation: 1123420
A generator expression:
cleaned = [i for i in (word.strip() for word in words) if i]
Using filter()
and map()
:
cleaned = filter(None, map(str.strip, words))
The latter produces a generator in Python 3; apply list()
to it or combine map()
with a list comprehension:
cleaned = [i for i in map(str.strip, words) if i]
Upvotes: 11