Is there an official name for a list comprehension with multiple for clauses?

This is a nested for loop that builds a nested list:

transposed = []
for i in range(4):
    transposed_row = []
    for row in matrix:
        transposed_row.append(row[i])
    transposed.append(transposed_row)

And this is the equivalent nested list comprehension according to the documentation:

transposed = [[row[i] for row in matrix] for i in range(4)]

And this is a nested for loop that builds a flat list:

transposed_flattened = []
for i in range(4):
    for row in matrix:
        transposed_flattened.append(row[i])

But then what do you call the equivalent list comprehension with multiple for clauses?

transposed_flattened = [row[i] for i range(4) for row in matrix]

I used to call it a nested list comprehension when I first learned Python but then learned that officially a nested list comprehension refers to one that actually builds a nested list.

Is there a good name for it that’s both concise and descriptive? Is it even worth giving it a name (instead of keeping the status quo of calling it a “list comprehension with multiple for clauses”)?

Does this kind of comprehension have any use cases aside from iterator flattening? I can’t recall ever having seen them used for anything else. I suppose they could be called ‘flattener comprehensions’.

Though personally, I would name them ‘antipatterns’. I must admit that single-level multi-for comprehensions do not fit neatly in my brain. Every time I come across one, I have to stop and think about what it’s doing.

For whatever reason, I find this perfectly clear:

transposed = [[row[i] for row in matrix] for i in range(4)]

But I strongly prefer this flattening idiom over the multi-for variant:

transposed_flattened = list(itertools.chain.from_iterable(transposed))
1 Like

Two dimensional list comp? I’d just call it a list comp, and it so happens that this one contains two nested loops, but it doesn’t really matter.

1 Like

Documentation says that the above is a nested list comprehension as [row[i] ...] is a complete comprehension nested in the outer one.

Reading other docs, (the grammar), , there is no name explicitely mentioned but it could be described as a (non-nested), list comprehension with two for-clauses.

Good suggestion. I would probably call it a “flattening list comprehension” since that’s indeed what it mostly does.

That’s fine if you have transposed already stored as an intermediate list of lists, but would look comparatively uglier than a flattening list comprehension if we want to avoid an intermediate list:

transposed_flattened = list(itertools.chain.from_iterable(
    (row[i] for row in matrix) for i in range(4)
))

That sounds to me more like what [[row[i] for row in matrix] for i in range(4)] is.

It is nested in the sense that it is essentially syntax sugar for a nested for loop even though the output is non-nested.

Yes, it’s called “too complicated for me.” :wink:

Comprehensions (list, dict) are fine for small things, as they are compact, but that compactness becomes obfuscation to my mind when they start to nest. (Do they then produce baby comprehensions? What do comprehensions use to make their nests?)

There are probably a couple aphorisms in the Zen of Python which touch on this idea.

2 Likes

Of course. For example Cartesian products.

2 Likes

Right. I would also strongly prefer the itertools version over the comprehension for that use case.

For pure Cartesian products I usually do, too. But think of stuff like [x+y for x in xs for y in f(x)].

1 Like

I sometimes use this but I always find myself wanting to write the loops in reverse order:

[x+y for y in f(x) for x in xs]
2 Likes

There is nesting in the for loop but not in the comprehension, (which is what I was trying to convey). :slight_smile:

1 Like

Not an answer, because you ask about “official”, but it would be a comprehension in which the formula is “doubly quantified”, if one wanted to inherit from set theory/logic not only the name comprehension, but also the description of your specific case.

1 Like