Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding nested list comprehension

I want to understand nested list comprehension. Below, I listed a list comprehension expression and their for loop equivalent.
I wonder if my understanding is correct on those.

For example,

[(min([row[i] for row in rows]),max([row[i] for row in rows])) 
for i in range(len(rows[0]))]

is equivalent to

result=[]
for i in range(len(rows[0])):
  innerResult=[]
  for row in rows:
    innerResult.append(row[i])
  innerResult2=[]
  for row in rows:
    innerResult2.append(row[i])
  tuple=(min(innerResult), max(innerResult2))
  result.append(tuple)

If I may generalize, I guess

[exp2([exp1 for x in xSet]) for y in ySet]

form can be translated to the following. (I hope I'm correct on this)

result=[]
for y in ySet:
  innerResult =[]
  for x in xSet:
    innerResult.append(exp1)
  exp2Result = exp2(innerResult)
  result.append(exp2Result)

For simpler case,

[exp1 for x in xSet for y in ySet] 

is equal to

result=[] 
for x in xSet:
  for y in ySet: 
    result.append(exp1)

whereas,

[[exp1 for x in xSet] for y in ySet]

is equal to

result=[]
for y in ySet:
  innerResult=[]
  for x in xSet:
    innerResult.append(exp1)
  result.append(innerResult)

I asked a similar question on Equivalent for loop expression for complex list comprehension
The answers given there reconstruct the form after understanding what it does internally.
I'd like to know how it works systematically so I can apply the concept to other slightly varying examples.

like image 696
eugene Avatar asked Nov 08 '11 11:11

eugene


People also ask

What is a nested list comprehension?

It is a smart and concise way of creating lists by iterating over an iterable object. Nested List Comprehensions are nothing but a list comprehension within another list comprehension which is quite similar to nested for loops.

What is nested list explain with example in Python?

A nested list is a list within a list. Python provides features to handle nested list gracefully and apply common functions to manipulate the nested lists. In this article we will see how to use list comprehension to create and use nested lists in python.

What is list comprehension and how is it useful?

List comprehension is an elegant way to define and create lists based on existing lists. List comprehension is generally more compact and faster than normal functions and loops for creating list. However, we should avoid writing very long list comprehensions in one line to ensure that code is user-friendly.


2 Answers

Indeed, you are correct. This is described in detail in the Expressions section in the Python Language Reference.

Note especially the order of nesting of several fors in a single list comprehension, which is always left-to-right:

>>> matrix = [[1, 2], [3, 4]] >>> [item for item in row for row in matrix] # oops! Traceback (most recent call last):   File "<pyshell#1>", line 1, in <module>     [item for item in row for row in matrix] NameError: name 'row' is not defined >>> [item for row in matrix for item in row] # nesting is in left-to-right order [1, 2, 3, 4] 
like image 70
taleinat Avatar answered Oct 15 '22 19:10

taleinat


The short answer is: yes, you are correct in your understanding.

There's only a catch: the way you normally use nested list comprehension in python code is to operate on multidimensional arrays.

A typical example is when you operate on matrices:

>>> matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] >>> [[el - 1 for el in row] for row in matrix] [[0, 1, 2], [3, 4, 5], [6, 7, 8]] 

As you can see the "nesting" works by operating on each dimension of the matrix.

In the examples you provided, it seems that ySet [unfortunate name btw, as sets are one of the types provided with python] is just a generic counter, which makes a bit harder to follow what is going on under the hood.

As for your first example:

>>> rows = ([1, 2, 3], [10, 20, 30]) >>> [(min([row[i] for row in rows]),max([row[i] for row in rows])) for i in range(len(rows[0]))] [(1, 10), (2, 20), (3, 30)] 

You might wish to look into the zip built-in function:

>>> zip(rows[0], rows[1]) [(1, 10), (2, 20), (3, 30)] 

or for maximum brevity and elegance:

>>> zip(*rows) [(1, 10), (2, 20), (3, 30)] 

HTH!

like image 27
mac Avatar answered Oct 15 '22 19:10

mac