I can’t think of how many times have just wondered about how awesome the python’s list comprehensions are. I found them extremely handy while I was preprocessing data for my data visualisation project.
Let me share with you some examples, general syntax and some nifty tricks.
Simple list comprehension example
Create list of numeric values ( this example is quite useless but illustrative for beginning )
1 |
[i for i in xrange(4)] |
1 |
[0, 1, 2, 3] |
The code is interpreted as : “run interation for i, and in each iteration, append i to the list”. Therefore we can go crazy with how we are iterating. We can iterate through some list or generator. Anything that’s iterable.
Process iteration result before appending into list
We can however play much more with the results of the iterations which we put into the created list. For example we may want to create list of powers of 2. We can simply do
1 |
[2**i for i in xrange(12)] |
1 |
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048] |
Or even call some function to process the result of iteration somehow.
1 |
[len(str(2**i)) for i in xrange(12)] |
1 |
[1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4] |
This example gives us array of numbers saying how many characters powers of 2 got.
Use custom generators with list comprenesions
Using generators we can make our list comprehension more readable. We can define custom generator and use it
1 2 3 4 5 6 7 |
def PowerOfTwoGenerator(upTo): i=1 while(i<upTo): yield 2**i i+=1 [i for i in PowerOfTwoGenerator(12)] |
1 |
[2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048] |
Use conditions for processing iteration result
When we receive the result from the iteration, we can do more complex things with it thanks to conditions. Like this :
1 |
[ (a if a%2==0 else a*1000) for a in [1,2,3,4,5,6,7] ] |
1 |
[1000, 2, 3000, 4, 5000, 6, 7000] |
Use conditions to filter out appended iteration results
When the condition in previous example is evaluated, it’s for sure that >SOME< value will be added to the list. However, sometimes we might want to filter out values we receieve from generator or iterated list. We can filter out even values
1 |
[a for a in [1,2,3,4,5,6,7] if a%2==0] |
1 |
[2, 4, 6] |
Iterate multiple variables
1 |
[[x,y] for x in [1,2,3] for y in [1,2]] |
1 |
[[1, 1], [1, 2], [2, 1], [2, 2], [3, 1], [3, 2]] |
Note that we just constructed the list of lists. Similarly we can also construct objects or dictionary
1 |
[{str(x):y} for x in [1,2,3] for y in [1,2]] |
1 |
[{'1': 1}, {'1': 2}, {'2': 1}, {'2': 2}, {'3': 1}, {'3': 2}] |
Trick: Nested list comprehension : Flattening list of lists
We may have nested lists we want to flat out. Let’s have
1 |
[[1, 2, 3], [1337, 666, 42], [7, 8, 9]] |
To flat out, we can use nested list comprehension.
1 |
[item for sublist in [[1, 2, 3], [1337, 666, 42], [7, 8, 9]] for item in sublist] |
1 |
[1, 2, 3, 1337, 666, 42, 7, 8, 9] |
The syntax may be a bit intimidating on the first glance. If you look closer however makes perfect sence.
I’ll add parenthesis to make it little bit more readable
1 |
[(item) for sublist in [[1, 2, 3], [1337, 666, 42], [7, 8, 9]] for item in sublist] |
Now we need to realise that each element of iterated list is also list. This list element we called sublist. And then we use second iteration to iterate each element of this sublist : for item in sublist
.
This is actually works pretty much the same as previous example
1 |
[{str(x):y} for x in [1,2,3] for y in [1,2]] |