Python Forum

Full Version: reduce nested for-loops
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Pages: 1 2
Hi,

i have lots of "search"-loops which looks like this:
            for b in a.list_of_bs:
                for c in b.list_of_cs:
                    for d in c.list_of_ds:
                        do_something()
This is a clear code smell. So how could this be simplified. Any idea?
The code doesn't look awful to me. But you want to do something for each "d", and those are nested way down inside a hierarchical datastructure. If you need to do this with any frequency, the items should be more accessible.

In isolation, it's hard to make suggestions. But perhaps you should instead have a collection of objects, each of which has the "b", "c" and "d" information. Then you can just iterate over that collection.

So I'd focus on the data and the data layout, not the specific set of loops shown.
Yes, you can:

from itertools import product


for a, b, c in product(a.list_of_bs, b.list_of_cs, c.list_of_ds):
    do_something(a, b, c)
Docs: itertools.product
(Mar-15-2023, 11:30 AM)DeaD_EyE Wrote: [ -> ]Yes, you can:

from itertools import product


for a, b, c in product(a.list_of_bs, b.list_of_cs, c.list_of_ds):
...

I don't think "b" or "c" are separately available objects (since they're just the loop variables in the original code).
Plus the OP wants to dig down to list_of_ds, not create tuples.
(Mar-15-2023, 11:30 AM)DeaD_EyE Wrote: [ -> ]Yes, you can:

from itertools import product


for a, b, c in product(a.list_of_bs, b.list_of_cs, c.list_of_ds):
    do_something(a, b, c)
Docs: itertools.product

This didnt work, since the "xxx is referenced before assignment" error occurs.
(Mar-15-2023, 02:35 PM)bowlofred Wrote: [ -> ]I don't think "b" or "c" are separately available objects (since they're just the loop variables in the original code).

I saw it too late. The names of the objects are a, b, c which do have the attribute list_of_xx. After the first iteration, the names are rebound to the elements from those three objects. This fails.

Better example:

from itertools import product


card_colors = "♥♦♠♣"
card_values = list(map(str, range(1, 11)))
card_values += "KJQ"

for color, value in product(card_colors, card_values):
    print(f"{color} {value}")
(Mar-14-2023, 09:24 PM)bowlofred Wrote: [ -> ]The code doesn't look awful to me.

OK, accepting this. But normally i have more that only 3 nested loops. When there's > 8, the pylint complains about it.
If your code is so deep nested, there is maybe a different problem.
If the structure is deep nested, you could also create a list/tuple with all elements, which should be used for product-iteration.
Then you can call product(*arguments).

from itertools import product

my_range1 = range(3)
my_range2 = range(2)
my_range3 = range(4)
my_range4 = range(2)

my_ranges = (my_range1, my_range2, my_range3, my_range4)
for values in product(*my_ranges):
    print(values)
But maybe you can solve your problem differently (XY-Problem?).
Depending on what do_something looks like, there is always list comprehension...

alist = [1,2,3]
blist = [4,5,6]
clist = [7,8,9]

print([element_c for element_c in clist for element_b in blist for element_a in alist])
Pages: 1 2