We’ve seen how to create and manipulate lists in Python. There is a special way of creating a list that is concise and powerful. This is list comprehension.
The syntax for list comprehension is
[expression for item in iterable if condition == True]
It’s important to remember to put a list comprehension inside square brackets. If you don’t, Python will throw an error.
List comprehension is easiest to understand by looking at a few examples. First, we consider a simpler way of generating a list of random numbers (which we did in the previous post). Earlier, we started with an empty list and then used a loop to successively generate and add random numbers to the list one at a time. Using list comprehension we can do this in a single statement, such as the following, which generates a list of 1000 random numbers:
from random import * ranList = [random() for x in range(1000)]
In this case, random()
is the ‘expression’, x
is the ‘item’ and range(1000)
is the iterable. The ‘if’ clause in list comprehension is optional, and in this example, is omitted.
Exercises
Explain why the following does not generate a sorted list referenced by the variable sortList
. How would you generate a sorted list using list comprehension?
from random import * sortList = [random() for x in range(1000)].sort()See answer
The x.sort()
function sorts the list x
and replaces x
with its sorted version. The sort()
function itself returns nothing, so sortList
is an empty variable. To generate a sorted list, we need to do the sort after creating the list, as in:
from random import * sortList = [random() for x in range(1000)] sortList.sort()
As an example of a list with a condition, consider:
[x for x in range(100) if x % 2 == 0 and 45 < x < 90]
Try to figure out what this list contains before you run it.
See answerThe condition restricts x
to values that have zero remainder when divided by 2 (that is, even numbers), for x
between 45 and 89. Thus the list is [46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88].
Now suppose we wanted to generate a list of numbers from 0 to 99, but with all the odd numbers replaced by -1. We could do this with a fancy for loop, but list comprehension provides a more elegant solution. To see how, we need to insert a condition into the ‘expression’ on the left, rather than have a condition after the ‘for’ statement. We have
[x if x % 2 == 0 else -1 for x in range(100)]
The expression is now x if x % 2 == 0 else -1
, which is evaluated for each value of x
in the range(100)
function (that is, from 0 to 99). It’s important to realize that the ‘expression’ must provide some value for every instance of x
generated by the for loop. If we left off the else -1
, we would get an error, since the statement doesn’t know what to do when x
is odd.
The condition can chain together several if statements to treat multiple cases rather than just two. For example, consider the statement:
[0 if x == 0 else 1/x if x % 2 == 0 else x * x for x in range(100)]
The list contains 0 if x == 0, if x is even (and not 0), and
if x is odd.
We can insert conditions in both the expression and after the for loop, as in:
[0 if x == 0 else 1/x if x % 2 == 0 else x * x for x in range(100) if x < 50]
This does the same as the previous example, except that the list is truncated at x = 49.
The important difference is that if we put a condition in the expression on the left, it must provide a return value for every value of x
presented to it. The condition on the right (after the for loop) acts as a filter, in that it determines which values of x
are presented to the expression on the left.
The syntax of a list comprehension is generally quite easy to understand, as it reads almost like an English sentence.
Exercises
1 – Given that the loop for x in string
iterates over each individual character in string
, write a program which asks the user to input several strings and for each string, prints out a list of the uppercase characters in that string.
while True: string = input('Enter some text (or \'quit\'):') if string == 'quit': break print([x for x in string if x.isupper()])
2. Write a program which asks the user to enter 3 numbers. The first is the number of random integers to generate, the second is the lower bound on these integers and the third is the upper bound. Use the randint(lower, upper)
function in the random
module to generate a list of the required number of random integers between lower and upper (both bounds inclusive).
From this list, derive three other lists: (1) a list containing even integers only; (2) a list containing odd integers only; (3) a list where all odd numbers have been replaced by -1 and all even numbers have been replaced by +1. Using these lists, calculate the averages of the even list and odd list, and the excess of evens over odds in the original list. You should use list comprehension to generate all the lists in your program. When calculating averages, you may use the sum()
function to add up the contents of a list.
from random import * while True: ranData = input('Enter the number of random ints and the lower and upper bounds (or \'quit\'):') if ranData == 'quit': break # Determine the number of ints and the upper and lower bounds ranData = ranData.split() numRands = int(ranData[0]) lower = int(ranData[1]) upper = int(ranData[2]) # Generate the list of random ints rands = [randint(lower, upper) for x in range(numRands)] # Generate the sublists of even and odd ints evens = [x for x in rands if x % 2 == 0] odds = [x for x in rands if x % 2 == 1] # Find the averages of evens and odds averEvens = sum(evens) / len(evens) averOdds = sum(odds) / len(odds) print('Average of evens:', averEvens) print('Average of odds:', averOdds) # Generate the list with +-1 for even/odd plusMinus = [-1 if x % 2 == 1 else +1 for x in rands] # Just sum this list to find the excess of evens print('Excess of evens:', sum(plusMinus))
To calculate the excess of evens over odds, we could also find the difference in length between the lists evens
and odds
, as in len(evens) - len(odds)
. Doing it as in the solution above gives you a bit more practice using list comprehensions, though.