Jonathan Vanasco
Jonathan Vanasco

Reputation: 15680

Python - are there other ways to apply a function and filter in a list comprehension?

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.

update

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

Answers (2)

Open AI - Opting Out
Open AI - Opting Out

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

Martijn Pieters
Martijn Pieters

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

Related Questions