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.
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
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 answer
The 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.
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) lower = int(ranData) upper = int(ranData) # 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
odds, as in
len(evens) - len(odds). Doing it as in the solution above gives you a bit more practice using list comprehensions, though.