Different loop order for list comprehension

Viewed 38

Consider the following:

xtest=np.arange(0,10)
ytest=np.arange(0,3)
zValuesBisBis=[[j for j in xtest] for i in ytest]
zValuesBisBisBis=[j for j in xtest for i in ytest]
print(zValuesBisBis)
print(zValuesBisBisBis)

It returns me respectively:

[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]]

[0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9]

And I don't understand why the loop order is changed between the two. I mean the content of the list obviously are not the same (one is a list of list while the other is a list of number). But the ordering of the loop should be identical, i.e I would expect to have the second print to be the "flattened" version of the first one.

Why such behavior ?

2 Answers

The [[j for j in xtest] for i in ytest] forces the inner loop (forcing the j loop to be the inner loop). The [j for j in xtest for i in ytest] leaves the inner loop as implied, which ends up being the rightmost loop, the i loop.

See the docs for examples of how multiple loops are evaluated.

If we desugar the comprehension, we get something like below.

# arr = [[j for j in xtest] for i in ytest]
arr = []
for i in ytest:
    t = []
    for j in xtest:
        t.append(j)
    arr.append(t)
# arr = [j for j in xtest for i in ytest]
arr = []
for j in xtest:
    for i in ytest:
        arr.append(j)

As you can see, the second one actually nests the loop in a straight way, rather than the reverse one you expected.

Related