Nov. 7, 2020

List comprehension with nested conditions

List comprehension operates on each element of a sequence with conditional expressions to generate a new sequence. There can be hierarchy of loops and conditions that transforms, or filters the original elements.

Rules of comprehension

List comprehension can generate a sequence derived from conditional expressions. The critical elements are an expression to operate on values from a loop, with optional conditions to filter values.

Py3: Comprehension rules

new_list = [expression(a,b...)
iterator_a conditions
nested_iterator_b conditions...]

Where;
expression: x ** 2
iterator: for x in range(6)
condition: if x % 2 == 1

#   complete statement
new_list = [x**2 for x in range(6) if x % 2 == 1]
#= [1, 9, 25]

Notes: Operating on a sequence of elements

List comprehension takes a list of elements and operates on each of them, modifying them using conditional expressions to create a new sequence.

Single iterator

List comprehensions with values derived from single iterator.

Py3: Single comprehension loop

#   repeat an element
x = [0 for i in range(5)]
#= [0,0,0,0,0]

#   sequence of elements
x = [i for i in range(5)]
#= [1,2,3,4,5]

#   computed values from an expression
x = [i**2 for i in range(5)]
#= [1,4,9,16,25]

Notes: Single loop comprehension

A simple list comprehension can create a repeated sequence with same or unique elements. Computation can be for each element using closed form expressions which generate a single hashable value.

Nested comprehension loops

Independent loops generate values independently which may be coupled together

Py3: Independent comprehension loops

#   outer loop values
x = [i for i in range(1,4) for j in range(2)]
#= [1,2,3,1,2,3]

#   inner loop values
x = [i for j in range(2) for i in range(1,4)]
#= [1,1,2,2,3,3]

#   tuples with inner and outer loops
x = [(i,j) for i in range(3) for j in range(2)]
#= [(0,0),(0,1),(1,0),(1,1),(2,0),(2,1)]

#   coupled expressions with two independent loops
x = [i*j for i in range(3) for j in range(2)]
#= [0,0,0,1,0,2]

#   comprehension over lists of functions and numbers
#   each function operating on list of numbers
nums = [5, 7, 2]
funcs = [lambda x:x*2, lambda x:x/2, lambda x:3*x]
x = [f(n) for f in funcs for n in nums]
#= [10, 14, 4, 2.5, 3.5, 1.0, 15, 21, 6]

#   nested comprehension over list of functions and values
#   nested list of function values for each element
nums = [2, 3, 4]
funcs = [lambda x:x, lambda x:x/2, lambda x:x**x]
x = [[f(n) for n in nums] for f in funcs]
#= [[2,3,4], [1.0,1.5,2.0], [4,27,256]]

Dependent loops, where one loop uses values from another.

Py3: Dependent comprehension loops

#   expressions with two connected loops
#   tuples of inner for each outer
x = [(i,j) for i in range(4) for j in range(i)]
#= [(1,0), (2,0), (2,1), (3,0), (3,1), (3,2)]

#   sequential loops
#   segment sentence to words, and words to letters
sentence = 'list comprehension is fun'
letters = [letter for word in sentence.split() for letter in word]
#= ['l','i','s','t','c','o','m','p','r','e','h',
#  'e','n','s','i','o','n','i','s','f','u','n']

#   nested connected comprehension of functions and values
#   three loops, for functions, numbers and power parameter
nums = [3, 2, 1]
funcs = [lambda x,p:p*x, lambda x,p:x/p]
x = [[f(n, p) for n in nums] for f in funcs for p in range(1,3)]
#= [[3, 2, 1], [6, 4, 2], [3.0, 2.0, 1.0], [1.5, 1.0, 0.5]]

Notes: Examples for nested loop comprehension

List comprehension can done over two or more nested loops, which can be independent or dependent on each other. Examples show simple nested loops and more complex loops of functions and values which operate as parameters for each other.

Conditional comprehension

Comprehension with logical conditions for elements from iterators.

Py3: Comprehension with condition

#   operate if condition is met: filter
nums = [0,1,2,4,6,7,8]
x = [i for i in nums if i % 2 == 0]
#= [0, 2, 4, 6, 8]

#   ternary expression
#   each element produces output from one of the two expressions
x = [i if i%2==1 else 'x' for i in range(9)]
#= ['x',1,'x',3,'x',5,'x',7,'x']

#   applying alternating function
#   capitalize alternate words
txt = 'alternate lower and upper case'
words = txt.split()
x = [s.lower() if e%2==0 else s.upper() for e,s in enumerate(words)]
#= ['alternate','LOWER','and','UPPER','case']

#   select number pairs when they are unequal
x = [(i,j) for i in range(3) for j in range(3) if i!=j]
#= [(0,1), (0,2), (1,0), (1,2), (2,0), (2,1)]

#   conditional inner loop for odd outer numbers
x = [(i,j) for i in range(4) if i%2==1 for j in range(5,7)]
#= [(1,5), (1,6), (3,5), (3,6)]

Notes: Conditional comprehension

List comprehension with conditions can determine when an expression is evaluated, or which expression gets evaluated. The inner loop can also be made to operation on conditions derived from outer loop.