0

Is there a way to reduce the indentation when using nested loops, as per below?

for source_i in sources:
    for source_j in sources:
        for ni in source_i.nodes:
            for nj in source_j.nodes:
                if ni != nj:
                    do_thing(ni, nj)
Zeophlite
  • 1,607
  • 3
  • 19
  • 36
  • Move the `do_thing` line to the beginning with a `[` before it; take out all new lines and colons; add a `]` to the end. Voila! But please don't do that. List comprehensions are easy ways to create lists. It is not a good idea to create a list of the returns of `do_thing(...)` if you aren't going to use it. List comprehensions should be used for creating lists, not for their side effects. – zondo Jul 06 '16 at 11:19

2 Answers2

2
for source_i in sources:
    for source_j in sources:
        pass

This is the same thing as iterating through the pairs in the Cartesian product of sources and itself. This can be written in one line by importing itertools:

import itertools
for (i,j) in itertools.product(sources, repeat=2):
    pass

Same pattern here:

for ni in i.nodes:
    for nj in j.nodes:
        pass

This can be rewritten as:

for (ni, nj) in itertools.product(i.nodes, j.nodes):
    pass

So now you can nest them:

import itertools
for (i,j) in itertools.product(sources, repeat=2):
    for (ni, nj) in itertools.product(i.nodes, j.nodes):
        if ni != nj:
            do_thing(ni, nj)
erip
  • 16,374
  • 11
  • 66
  • 121
  • 1
    `product(sources, sources)` can also be written as `product(sources, repeat=2)` - comes handy especially when we want more than a 2-dimensional product of an iterable with itself. – plamut Jul 06 '16 at 11:49
  • @plamut Yes, I have it at the top and forgot to copy it down. :) Thanks for the tip. – erip Jul 06 '16 at 11:50
2

Yes, one way to replace nested loops is to use itertools.product:

from itertools import product

for source_i, source_j in product(sources, repeat=2):
  for ni, nj in product(source_i.nodes, source_j.nodes):
      ...

The product function does a "Cartesian product of input iterables" (directly from the docs).

plamut
  • 3,085
  • 10
  • 29
  • 40