Double Iteration in List Comprehension

Double Iteration in List Comprehension

Gee, I guess I found the anwser: I was not taking care enough about which loop is inner and which is outer. The list comprehension should be like:

[x for b in a for x in b]

to get the desired result, and yes, one current value can be the iterator for the next loop.

python list comprehension double for

Lets break it down.

A simple list-comprehension:

[x for x in collection]

This is easy to understand if we break it into parts: [A for B in C]

  • A is the item that will be in the resulting list
  • B is each item in the collection C
  • C is the collection itself.

In this way, one could write:

[x.lower() for x in words]

In order to convert all words in a list to lowercase.


It is when we complicate this with another list like so:

[x for y in collection for x in y] # [A for B in C for D in E]

Here, something special happens. We want our final list to include A items, and A items are found inside B items, so we have to tell the list-comprehension that.

  • A is the item that will be in the resulting list
  • B is each item in the collection C
  • C is the collection itself
  • D is each item in the collection E (in this case, also A)
  • E is another collection (in this case, B)

This logic is similar to the normal for loop:

for y in collection:     #      for B in C:
for x in y: # for D in E: (in this case: for A in B)
# receive x # # receive A

To expand on this, and give a great example + explanation, imagine that there is a train.

The train engine (the front) is always going to be there (the result of the list-comprehension)

Then, there are any number of train cars, each train car is in the form: for x in y

A list comprehension could look like this:

[z for b in a for c in b for d in c ... for z in y]

Which would be like having this regular for-loop:

for b in a:
for c in b:
for d in c:
...
for z in y:
# have z

In other words, instead of going down a line and indenting, in a list-comprehension you just add the next loop on to the end.

To go back to the train analogy:

Engine - Car - Car - Car ... Tail

What is the tail? The tail is a special thing in list-comprehensions. You don't need one, but if you have a tail, the tail is a condition, look at this example:

[line for line in file if not line.startswith('#')] 

This would give you every line in a file as long as the line didn't start with a hashtag (#), others are just skipped.

The trick to using the "tail" of the train is that it is checked for True/False at the same time as you have your final 'Engine' or 'result' from all the loops, the above example in a regular for-loop would look like this:

for line in file:
if not line.startswith('#'):
# have line

please note: Though in my analogy of a train there is only a 'tail' at the end of the train, the condition or 'tail' can be after every 'car' or loop...

for example:

>>> z = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
>>> [x for y in z if sum(y)>10 for x in y if x < 10]
[5, 6, 7, 8, 9]

In regular for-loop:

>>> for y in z:
if sum(y)>10:
for x in y:
if x < 10:
print x

5
6
7
8
9

How to frame two for loops in list comprehension python

This should do it:

[entry for tag in tags for entry in entries if tag in entry]

Nested List Comprehension - Double Iteration - Classic CS Problems in Python - Chapter 3 - Word Search

test_list_comp = [locs for values in test.values() for locs in values]

Is equivalent to:

test_list_comp = []

for values in test.values():
for locs in values:
test_list_comp.append(locs)

List comprehensions are evaluated from left to right.

Nested list comprehension not the same as nested for loop

Your list comprehension doesn't do anything as it does not run without i already been defined outside the list comprehension.

To achieve what you want (and yes, this is counter intuitive ) you need to do this:

[j  for i in range(1,5) for j in range(0,i)]

This will yield:

[0, 0, 1, 0, 1, 2, 0, 1, 2, 3]

which is the same order as your nested for loops.

2 List Comprehension in python

When using list comprehension you're building a new list. You don't need to use append.

You don't need to use an interator with list indices and range either.

The inner loop would look like this :

[value*s for value in box]

Here we're building a new list which be the original list with each item multiplied by your s variable.

Now, we need to create a such list for each box in your current_boxes.

The outer loop that would do this may be like :

[box for box in current_boxes]

When combined :

all_boxes = [[value*s for value in box] for box in current_boxes]


Related Topics



Leave a reply



Submit