Posts: 11
Threads: 6
Joined: Apr 2020
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?
Posts: 1,583
Threads: 3
Joined: Mar 2020
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.
Gribouillis likes this post
Posts: 2,117
Threads: 10
Joined: May 2017
Mar-15-2023, 11:30 AM
(This post was last modified: Mar-15-2023, 11:31 AM by DeaD_EyE.)
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
Posts: 1,583
Threads: 3
Joined: Mar 2020
(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).
Posts: 6,756
Threads: 20
Joined: Feb 2020
Plus the OP wants to dig down to list_of_ds, not create tuples.
Posts: 11
Threads: 6
Joined: Apr 2020
(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.
Posts: 2,117
Threads: 10
Joined: May 2017
Mar-16-2023, 09:23 AM
(This post was last modified: Mar-16-2023, 09:23 AM by DeaD_EyE.)
(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}")
Posts: 11
Threads: 6
Joined: Apr 2020
(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.
Posts: 2,117
Threads: 10
Joined: May 2017
Mar-16-2023, 10:56 AM
(This post was last modified: Mar-16-2023, 10:57 AM by DeaD_EyE.)
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?).
bowlofred likes this post
Posts: 1,356
Threads: 2
Joined: May 2019
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])
|