Welcome, guest | Sign In | My Account | Store | Cart

List comprehensions, like functions, return values. They can even initialize and accumulate variables.

Initialization in these comprehension takes the form “j for j in (n,)” where ‘n’ is any value and is equivalent to the “j = n” statement. Initialization happens only once at the top level of these comprehensions. Accumulation has the form of “[j for j in (ji,)]” which is equivalent to j *= i where ‘’ can be any associative operator and ‘i’ any value.

Python, 14 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
nl= (2,3,6,18)

# The sum comprehension
[ [ [j for j in (j+i,) ] for i in nl] for j in (0,) ]  [0][-1][0]
# results in 29 or [[[2], [5], [11], [29]]]  without   [0][-1][0] at the tail

# the product comprehension
[ [ [j for j in (j*i,)] for i in nl ] for j in (1,) ]  [0][-1][0]
# results in 648 when nl = (2,3,6,18)

# a factorial comprehension
fac= 6
[ [ [j for j in (j*i,)] for i in range(2,fac+1)] for j in (1,)]   [0][-1][0]
# results in 720

I don’t know of what practical use anonymous list comprehension functions are. They suffer the same weaknesses that is causing the removal of reduce from Python. The sum and product functions are better except I can’t find the product function in my Python.

4 comments

Steven Bethard 16 years, 4 months ago  # | flag

Why all the nested list comprehensions so that you need [0][-1][0] at the end? Why don't you just use multiple fors in the same list comprehension? Then you only need the final [-1]:

# sum
nl = [2, 3, 6, 18]
[j for j in [0] for i in nl for j in [j + i]][-1]

# product
nl = [2, 3, 6, 18]
[j for j in [1] for i in nl for j in [j * i]][-1]

# factorial
fac = 6
[j for j in [1] for i in xrange(2, fac+1) for j in [j*i]][-1]
Frank P Mora (author) 16 years, 4 months ago  # | flag

Thanks. I am astounded. I so wanted what you so elegantly achieved. To make them work you had to swap the left and right ‘for’ clauses to remove the nesting. I very incorrectly assumed that would not work. Your functions are so nice and easy they might even find use. You could be the DeMorgan of Python list comprehensions.

(Sorry for the typo: the first 'comprehension' should have ended in 's')

Frank P Mora (author) 15 years, 7 months ago  # | flag

The pattern with prefix functions. And, the pattern works just as effectly with prefix functions

>>> T=[set(s) for s in [(1,2,3,4,5),(2,3,4,5,6),(3,4,5,6,7),(4,5,6,7,8)]]

>>> f=set.intersection
>>> [ s for s in [f(*T[:2])] for i in range(2,len(T)) for s in [f(s,T[i])] ][-1]
set([4, 5])     ## issues the null set if no intersection between all given sets

>>> f=set.union
>>> [ s for s in [f(*T[:2])] for i in range(2,len(T)) for s in [f(s,T[i])] ][-1]
set([1, 2, 3, 4, 5, 6, 7, 8])

>>> # join
>>> T=[(1,2,3,4,5,6,7),(3,4,5,6,7),(5,6,7),(7,8,9,2,1,5)]

>>> [ s for s in [T[0]] for i in range(1,len(T)) for s in [s + T[i]] ][-1]
(1, 2, 3, 4, 5, 6, 7, 3, 4, 5, 6, 7, 5, 6, 7, 7, 8, 9, 2, 1, 5)

>>> T=["abcd","efgh","ijkl","mnop","qrst"]

>>> [ s for s in [T[0]] for i in range(1,len(T)) for s in [s + T[i]] ][-1]
'abcdefghijklmnopqrst'
Frank P Mora (author) 15 years, 7 months ago  # | flag

And with predicates.

>>> l=[20,30,40,50,60,70,80,90,1,2,3,4,5]

>>> # all function
>>> [ p for p in [l[0]>42] for i in range(1,len(l)) for p in [p and l[i]>42] ][-1]
False

>>> # any function
>>> [ p for p in [l[0]>42] for i in range(1,len(l)) for p in [p  or l[i]>42] ][-1]
True

This pattern is very general and regular, my favorite type.
Created by Frank P Mora on Tue, 12 Jul 2005 (PSF)
Python recipes (4591)
Frank P Mora's recipes (1)

Required Modules

  • (none specified)

Other Information and Tasks