List comprehensions (LCs) Note: Resurrected from another one of my places.
- Do you wince when you use map and filter because you can't figure out LCs?
- Do you rail against modernity and stick with for and if 's?
- Do you always have to have that smoking one-liner? Are you ashamed when you can't get it?
- Did you know that you can put comments in LCs ?
- Did you know that LCs can be split on to separate lines? Is that sacrilege?
- Which do you like better ... form (a), (b) or (c) ?
Basic LC forms |
---|
Traditional for loop c = [] for i in range(20): if (i > 5) and (i < 10): c.append(i**2)
The smokin' cryptic one-liner a = [i**2 for i in range(20) if i > 5 and i < 10]
The stacked, commented multi-liner b = [i**2 # do this for i in range(20) # using these if (i > 5) and # where this and (i < 10) # this is good ] |
Condition checking with numbers and conditions |
---|
Again, the three methods, but this time the condition checking is done upfront with an if-else clause. This query is simply checking to see whether elements in a list are all numbers. If True, return the number, if False, assign -999.
nums = [0,1,None,3,None,5,6] # the list of numbers to check
conventional approach >>> good = [] >>> for val in nums: ... if isinstance(val, (int,float)): ... good.append(val) ... else: ... good.append(-999) ...
basic list comprehension >>> good = [ val if isinstance(val,(int,float)) else -999 for val in nums] >>>
stacked list comprehension >>> good = [ ... val # return the value ... if isinstance(val,(int,float)) # if this is true ... else -999 # return this otherwise ... for val in nums # for each value in the list ... ]
in all cases >>> good [0, 1, -999, 3, -999, 5, 6] |
More on condition checking |
---|
Some times you want to perform an operation given certain conditions. In the example below, a check is made to ensure that "b" is not zero to avoid division by zero. If it is zero, then an alternate value is supplied.
There are two variants of the LC shown and the results are compared as a final step...examine closely. outer = [1,2] inner = [2,0,4] c = [[a, b, a*b, a*b/1.0] # divide 2 numbers (outer/inner) if b # if != 0 (0 is a boolean False) else [a,b,a*b,"N/A"] # if equal to zero, do this for a in outer # for each value in the outer list for b in inner # for each value in the inner list ] for val in c: # val[0],val[1],val[2])) print("a({}), b({}), a*b({}) a/b({})".format(*val )) d = [[[a,b,a*b,"N/A"], # do if False [a,b,a*b,a*b/1.0]][b!=0] # do if True ... then slice for a in outer for b in inner ] print("d == c??? {}".format(d==c)) a(1), b(2), a*b(2) a/b(2.0) a(1), b(0), a*b(0) a/b(N/A) a(1), b(4), a*b(4) a/b(4.0) a(2), b(2), a*b(4) a/b(4.0) a(2), b(0), a*b(0) a/b(N/A) a(2), b(4), a*b(8) a/b(8.0) d == c??? True |
The examples shown here are just the beginning. The reader should be aware that there are dictionary and set comprehensions as well. This topic will also serve as a gentle introduction to generators.
If you would like to see other examples, please send me a note.
Additions |
---|
What is the difference between a list comprehension and a set comprehension. Basically, a process step is the only thing sometimes. As seen below, the set_comp results are completed during the query, whereas the list_comp results in line 04 still need to have a set() operation applied after the fact, should a set truly be required.
>>> a = [1,2,1,1,2,3,3,2,1,1,1,2,3,4,9,8,1,7,7,7,7,7] >>> list_comp = [ i for i in a if i >3 ] >>> set_comp = { i for i in a if i > 3 } >>> list_comp [4, 9, 8, 7, 7, 7, 7, 7] >>> set_comp set([8, 9, 4, 7])
>>> a = [5,6,5,6,5,6,5,6,5,6,4,4] >>> b = [5,6] >>> lc = [ x*y for x in a for y in b] >>> sc = { x*y for x in a for y in b } >>> lc [25, 30, 30, 36, 25, 30, 30, 36, 25, 30, 30, 36, 25, 30, 30, 36, 25, 30, 30, 36, 20, 24, 20, 24] >>> sc {24, 25, 36, 20, 30} >>> |
I am becoming a fan of list comprehensions. I would like to see your basic examples for set comprehensions.