A list comprehension is a way to create a new Python list
from any iterable structure (often another list, but not necessarily). The syntax looks a lot like the construction of a list with known components.
[expression for variable in iterable if boolean_expression]
where if boolean
is optional.
Here are a couple of examples.
First, we create a list
from a range
l = [i for i in range(10)] print(type(l)) print(l)
Why would we want to do this? Python ranges are different than lists; in particular, while they are iterable, they are not mutable.
r = range(10) print(r) print(type(r)) r.append(10)
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
/tmp/ipykernel_759/2580088131.py in <module>
2 print(r)
3 print(type(r))
----> 4 r.append(10)
AttributeError: 'range' object has no attribute 'append'
Next, let's compute the squares of the first 10 positive integers.
[x**2 for x in range(10)]
Now, let's use a list comprehension to write a function that takes any iterable object as its first argument, and returns a list
of the values in that first argument that are divisible by the second argument.
def divisible_by (iterable, divisor): return [a for a in iterable if a % divisor == 0]
And now let's see if it works!
r = range(21) evens = divisible_by(r, 2) print(evens) by_seven = divisible_by(r, 7) print(by_seven)
It's not just numbers that we can process using list comprehensions. The following set of examples come from this site. First we define a string to operate on.
string = "Practice Problems to Drill List Comprehension in your Head"
Now let's write a list comprehension that finds the length of each of the words
[len(w) for w in string.split(" ")]
Figure out the longest word in the sentence
words = string.split(" ") word_lengths = [len(w) for w in words] longest = max(word_lengths) print(longest) [w for w in words if len(w) == longest]
[w for w in words if len(w) == max([len(w) for w in words])]
How many spaces are there in string
?
len([c for c in string if c == ' '])
It's impressive what we can read without vowels. What does string
look like without the vowels?
''.join([c for c in string if c not in ['a', 'e', 'i', 'o', 'u']])
Find all of the words in string
that are less than 5 letters
[w for w in string.split(' ') if len(w) < 5]
Write this as a function, and call it to get the same result as above.
def words_less_than(string, delimiter=' ', length=5): return [w for w in string.split(delimiter) if len(w) < length]
print(words_less_than(string, length=5)) print(words_less_than(string, length=9))
Suppose there was no list comprehension in Python. How could we write it as a function ourselves?
def list_comprehension(iterable, expression_function=None, contains_function=None ): result = [] for i in iterable: if contains_function == None or contains_function(i)==True: if expression_function == None: result.append(i) else: result.append(expression_function(i)) return result
Try it out a few times.
print(list_comprehension(range(0,10))) print(list_comprehension(range(0,10), expression_function=lambda x: x**2)) print(list_comprehension(range(0,10), expression_function=lambda x: x**2, contains_function=lambda x: x < 5))
Finally, what if we give some default arguments for expression_function
and contains_function
.
def list_comprehension(iterable, expression_function=lambda x:x, contains_function=lambda x:True): result = [] for i in iterable: if contains_function(i)==True: result.append(expression_function(i)) return result
Try it out a few times.
print(list_comprehension(range(0,10))) print(list_comprehension(range(0,10), expression_function=lambda x: x**2)) print(list_comprehension(range(0,10), expression_function=lambda x: x**2, contains_function=lambda x: x < 5))