List comprehensions (listcomps) dict comprehensions (dictcomps) and set comprehensions (setcomps) are a shortcut to construct lists, dict and sets in a single line.
In [3]:
from pprint import pprint
import numpy as np
In [9]:
myList = [(3, 2), (40, 12), (-5, 4), (-6, -21), (-7, 23)]
x0 = 44
y0 = 13
We might compute the distance between the coordinates x0, y0 to each of the points implied by the coordinate tuples in myList
using a for-loop as follows:
In [15]:
r = []
for x, y in myList:
r.append(np.sqrt((x - x0)**2 + (y - y0)**2))
print(r)
Now the same thing, but with a list comprehension:
In [19]:
r = [ np.sqrt((x - x0)**2 + (y - y0)**2 ) for x, y in myList]
print(type(r))
print(r)
When parenthesis ( ) are used instead of square brackets, then it's not a tuple that is generated, but we createa generator objects:
In [18]:
r = (np.sqrt((x - x0)**2 + (y - y0)**2 ) for x, y in myList)
print(type(r))
r is a generator object that we can now use wherever we need the list that it will generate upon request:
In [20]:
r
Out[20]:
On the other hand, numerical stuff is mostly better done using numpy functionality such as numpy arrays.
Let's generate a deck of playing cards and shuffle them.
A deck of cards looks like this:
In [76]:
from random import shuffle
cards1 = ['Clubs', 'Diamonds', 'Hearts', 'Spades']
cards2 = ['Ace', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'Jack', 'Queen', 'King']
# gnerate the deck
cards = [c1 + '_' + c2 for c1 in cards1 for c2 in cards2]
shuffle(cards) # shuffle the cards
#pprint(cards) # show them
print("\nShuffled playing cards:\n")
for i in range(13):
for j in range(4):
print("{:20}".format(cards[4 * i + j]), end="")
print()
List comprehensions are especially useful for inspection of objects, to see their public attributes:
In [23]:
[p for p in dir(r) if not p.startswith('_')]
Out[23]:
We could also use it to for a better introspection of the methods of an object like so. For this we can use the inspect module with the function getmembers
. With a small list comprehension we can easily idendity the type of the public attributes of the list:
In [70]:
from inspect import getmembers
[p for p in getmembers(myList) if not p[0].startswith('_')]
Out[70]:
In [81]:
myList = [p%5 for p in range(51)] # % computes remainder of a division
mySet ={p%5 for p in range(51)}
print(myList)
print()
print(mySet)
Dict comprehensions are similar to list comprehensions, but two values [key, value] must be supplied.
For example the list of tuples can be regarded as a list of x, y coordinates and now we want to use the first value as de key and the second values at its value.
In [1]:
myList = [(3, 2), (40, 12), (-5, 4), (-6, -21), (-7, 23)]
myDict1 = {key : value for key, value in myList}
myDict2 = {value : key for key, value in myList}
print(myDict1)
print(myDict2)
print()
pprint(myDict1) # sorts the keys
pprint(myDict2) # sorts the keys
More advanced comprehensions will be shown shortly when we deal with world population data in an extended example.
Let's first generate a tuple of tuples, each with three numbers.
In [1]:
from numpy import random
In [4]:
myTuples = tuple([tuple(random.randint(-5, 5, 3)) for i in range(20)])
pprint(myTuples)
Then find the tuple for which the seond field (that with index 1) is lowest.
In [5]:
import sys
m = myTuples[0] # initialize by taking the the first tuple, any other would do as well
for tp in myTuples:
if tp[1] < m[1]: # compare the field with that of the current minimum tuple
m = tp # if true then replace the current minimum tuple
print(m) # show the update mininum tuple
print("\nminimum in field 2 is: ",m)
Now a more elegant one using keyword key
In [6]:
def vcmp(tp):
x, y, z = tp
return y
min(myTuples, key=vcmp)
Out[6]:
Why does this work ?
In general with a list of arbitrary objects, comparing them is not defined, like in this case. We can, however, come around this, by defining how two of the objects in questions have to be compared to decide which of them is smallest. This comparison is then done using some value that is computed for each object. In this case it's the second value of the tuple that we compare between objects to decide which of them is smallest. The function computes this value. This function is than passed to the min function as the argment of key. What then happens, is that min runs along the list of tuples and for each of them computes the value for comparison using the passed function. These values are compared to decide which object is smallest. When done the smallest object is returned.
And the most concise way, using a lambda function:
In [9]:
min(myTuples, key = lambda x: x[1])
Out[9]:
How does it work?
A lambda function
is a so-called anonumous function
, in some languages also called a macro
. It takes one or more arguments and its body consists of a single expression, that returns a single value.
So the lambda function
lambda x: x[1]
is equivalent to
def vcmp(x): return x[1]
That's why it works.
Lambda functions come in handy at many places where simple processing is needed on the fly and there is no standard function to do it.
In [ ]: