Comprehensions¶
The list comprehension¶
If you write a for loop inside a pair of square brackets for a list, you magic up a list as defined. This can make for concise but hard to read code, so be careful.
result = []
for x in range(10):
result.append(2 ** x)
print(result)
is the same as
result = [2 ** x for x in range(10)]
print(result)
You can do quite weird and cool things with comprehensions:
[len(str(2 ** x)) for x in range(20)]
You can write an if
statement in comprehensions too:
[2 ** x for x in range(30) if x % 3 == 0]
Consider the following, and make sure you understand why it works:
"".join([letter for letter in "Eric Idle"
if letter.lower() not in 'aeiou'])
Comprehensions versus building lists with append
¶
This code:
result = []
for x in range(30):
if x % 3 == 0:
result.append(2 ** x)
print(result)
does the same as the comprehension above. The comprehension is generally considered more readable.
Comprehensions are therefore an example of what we call 'syntactic sugar': they do not increase the capabilities of the language.
Instead, they make it possible to write the same thing in a more readable way.
Everything we learn from now on will be either syntactic sugar or interaction with something other than idealised memory, such as a storage device or the internet. Once you have variables, conditionality, and branching, your language can do anything. (And this can be proved.)
Nested comprehensions¶
If you write two for
statements in a comprehension, you get a single array generated over all the pairs:
[x - y for x in range(4) for y in range(4)]
You can select on either, or on some combination:
[x - y for x in range(4) for y in range(4) if x >= y]
If you want something more like a matrix, you need to do two nested comprehensions!
[[x - y for x in range(4)] for y in range(4)]
Note the subtly different square brackets.
Note that the list order for multiple or nested comprehensions can be confusing:
[x + y for x in ["a", "b", "c"] for y in ["1", "2", "3"]]
[[x + y for x in ["a", "b", "c"]] for y in ["1", "2", "3"]]
Dictionary Comprehensions¶
You can automatically build dictionaries by using a list comprehension syntax, but with curly brackets and a colon:
{((str(x)) * 3): x for x in range(3)}
List-based thinking¶
Once you start to get comfortable with comprehensions, you find yourself working with containers, nested groups of lists and dictionaries, as the 'things' in your program, not individual variables.
Given a way to analyse some dataset, we'll find ourselves writing stuff like:
analysed_data = [analyse(datum) for datum in data]
analysed_data = map(analyse, data)
There are lots of built-in methods that provide actions on lists as a whole:
any([True, False, True])
all([True, False, True])
max([1, 2, 3])
sum([1, 2, 3])
One common method is map
, which works like a simple list comprehension: it applies one function to every member of a list.
[str(x) for x in range(10)]
map(str, range(10))
Its output is this strange-looking map
object, which can be iterated over (with a for
) or turned into a list:
for element in map(str, range(10)):
print(element)
list(map(str, range(10)))
We can use map
to process a set of data
through a analyse
function as:
analysed_data = list(map(analyse, data))
We'll learn more about map
and similar functions when we discuss functional programming later in the course.
Exercise: Occupancy Dictionary¶
Take your maze data structure. Write a program to print out a new dictionary, which gives, for each room's name, the number of people in it. Don't add in a zero value in the dictionary for empty rooms.
The output should look similar to:
{"bedroom": 1, "garden": 3, "kitchen": 1, "living": 2}