List comprehensions

Martin McBride, 2018-08-10
Tags comprehension list comprehension
Categories python language intermediate python

Declaring lists in Python is quite simple:

k = [0, 1, 2, 3]

But what if you needed a much longer list, where the elements followed some pattern, for example a list of all the numbers from 0 to 999?

You would probably use a list similar to this

k = []
for x in range(1000):

This code starts with an empty list, and the loop appends values 0, 1, 2 ... 999, one by one.

List comprehensions offer a shorthand way of doing this. Here is the same code written as a list comprehension:

k = [x for x in range(1000)]

As you can see, all the elements of the loop are there, just shortened an re-arranged a bit. The easiest way to understand it is to read it as an English sentence:

The elements of k are the values of x for every x in the range 0 to 999

You can also create a list based on some calculation using the value x, for example:

k = [x*x for x in range(1000)]

Fills the list with successive squared values (the final value is 999*999):

[0, 1, 4, 9, 16 ... 998001]

You don't have to use a range function, you can use any sequence, including another list:

a = [2, 3, 1, 5]
b = [x + 2 for x in a]

This adds 2 to each value in a, to create the corresponding value in b.

[4, 5, 3, 7]

Here is the general form for a simple list comprehension:


Where expression might be something like x + 2, and sequence might be a range, list, or in general any iterable. For each value x in the sequence, the expression is evaluated and the result added to the list.

Advantages of list comprehensions

A list comprehension is obviously a bit shorter than the equivalent loop, but it has other advantages:

  • It is more readable (when you get used to it).
  • The intent is clear - to initialise a list. A loop could be doing anything, you have to read it to check that it doesn't have any other side effects. A list comprehension just sets up the list, you know it isn't up to anything else.
  • For that reason, it is less error prone.
  • It is a Python expression, so you can incorporate it into other statements to keep you code short and readable.

Using conditions

Suppose we have an existing list of numbers, and we want to create a second list which excludes all the negative numbers. We might use this loop:

x = [1, -2, 4, 5, -3, -9, 0]
y = []
for n in x:
    if n >= 0:

Here, we check the value of n, and only append it to list y if it is not negative. But here is an alternative - we can use a list comprehension:

x = [1, -2, 4, 5, -3, -9, 0]
y = [n for n in x if n >= 0]

If you are starting to get used to list comprehensions, you might see that not only is this code shorter, it is also more readable.

As another example, let's find a list of square numbers which end in 6. Remember you can find the last digit of a number using modulo (%) 10. Here is the loop:

k = [x*x for x in range(1000) if x*x % 10 == 6]

Which gives

[16, 36, 196, 256, 576 ...

Here is the general form for a conditional list comprehension:


Where expression might be something like x*x, condition sequence is an iterable, and condition could be something like x >= 0. For each value x in the sequence, the condition is checked, and if it is true the expression is evaluated and the result added to the list.

Finally, just to show that it doesn't always have to be about numbers, let's extract a list of colour names which start with vowels (and, yes, I have picked some of the sillier ones from the CSS colour names):

u = ['aliceblue',
v = [s for s in u if s[0] in 'aeiou']

In this case, the condition is :

s[0] in 'aeiou'

giving the result:

['aliceblue', 'oldlace', 'olivedrab']

Creating 2D lists

What if the expression part of the comprehension returns a list itself? Such as this:

k = [[0]*4 for x in range(3)]

Well, this creates a list with 3 elements, where each element is a list [0, 0, 0, 0].

Remember, [0]*4 gives [0, 0, 0, 0]

This creates a 2D list:

[[0, 0, 0, 0],
 [0, 0, 0, 0],
 [0, 0, 0, 0],
 [0, 0, 0, 0]]

This is actually quite a useful recipe for creating 2D lists. The following doesn't work:

k = [[0]*4]*3   #Doesn't work!
k[1][2] = 3
print(k)        #[[0, 0, 3, 0], [0, 0, 3, 0], [0, 0, 3, 0]] Ooops!

This code doesn't work because it only creates the inner list once. The outer list contains 3 copies of the same inner list.

Now we can go a stage further, and use a second list comprehension as our expression:

k = [[x + y for y in range(3)] for x in range(3)]

Here is what it does:

  • The x loop runs 3 times, and on each pass through, the inner list comprehension executes.
  • The inner list comprehension creates a list of 3 elements with a value equal to y plus the current value of x.
  • The result is a 3 by 3 list where each element is equal to the sum of its column and row numbers.

[[0, 1, 2], [1, 2, 3], [2, 3, 4]]

Try these next two, and check what happens:

u = [[1 if x == y else 0 for y in range(3)] for x in range(3)]
v = [[0 for y in range(x + 1)] for x in range(3)]

Further reading

Here are a few variants you can look up if you are interested, which aren't cover here because they aren't as common:

  • Set comprehensions - like list comprehensions but they create a set (just use {} instead of []).
  • Dictionary comprehensions
  • Using nested for loops (two for loops to create a 1 dimensional list). Some people feel this is a step too far, and isn't really as readable as just using explicit loop code.

In addition, the built-in functions map and filter can do a similar job. They are less concise, but more flexible. It is often a matter of personal preference.

Tag cloud

2d arrays abstract data type alignment and array arrays bezier curve built-in function close closure colour comparison operator comprehension context conversion data types design pattern device space dictionary duck typing efficiency encryption enumerate filter font font style for loop function function plot functools generator gif gradient html image processing imagesurface immutable object index input installing iter iterator itertools lambda function len linspace list list comprehension logical operator lru_cache mandelbrot map monad mutability named parameter numeric python numpy object open operator optional parameter or path positional parameter print pure function radial gradient range recursion reduce rotation scaling sequence slice slicing sound spirograph str stream string subpath symmetric encryption template text text metrics transform translation transparency tuple unpacking user space vectorisation webserver website while loop zip

Copyright (c) Axlesoft Ltd 2020