Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nested FOR loops WITH initialized values, BUT continue entire range of list

I am trying to continue my nested for loop at some value after the process has begun. But after starting run the entire range of values for the remainder of the state space. Let's look at my example:

list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
list2 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
list3 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
list4 = [1, 2, 3, 4, 5, 6, 7, 8, 9]

# 9 x 9 x 9 x 9 = 6561 total values
# Let's say we want to start from the 500th value 
# This would mean:
# x=1, y=7, z=2, t=6

I tried setting values prior to for loops, however the for loop just rewrites them. I also tried the range() below, however that prevents it for everything. Is there any method to initialize nested loops at a certain iteration but maintain the range of the space??

counter = 0
list_of_names = []

for x in range(1, len(list1)):
    for y in range(7, len(list2)):
        for z in range(2, len(list3)):
            for t in range(6, len(list4)):
                Name = "A" + str(x) + " B" + str(y) + " C" + str(z) + " D" + str(t)
                list_of_names.append(Name)
                counter += 1
print(counter)
print(len(list_of_names))

My eternal gratitude, show me your genius...

like image 498
Doğa Altınışık Avatar asked Nov 23 '25 21:11

Doğa Altınışık


2 Answers

If I understand what you're looking for, you could modify your code like this:

for x in range(1, len(list1)):
    for y in range(7 if x==1 else 0, len(list2)):
        for z in range(2 if y==7 else 0, len(list3)):
            for t in range(6 if z==2 else 0, len(list4)):

That's pretty ugly, but it will work: the inner loop will cover only part of the list2 the first time, but all of list2 from then on.

You could wrap things up as a function that takes four lists and four start values, or a function that takes N lists and N start values, or, better, a function that takes N lists and a single overall start value and does the divmod to calculate the N start values.


However, it seems like there' a much simpler solution. Instead of doing the divmod arithmetic, just combine the whole iteration into a single loop with itertools.product:

for x, y, z, t in product(range(len(list1)), range(len(list2)), range(len(list3)), range(len(list4)):

… or maybe:

for x, y, z, t in product(*(range(len(l)) for l in (list1, list2, list3, list4))):

… or, better, loop over the lists themselves rather than their indices:

for x, y, z, t in product(list1, list2, list3, list4):

That last change doesn't work for your existing code, because you seem to want to print out the indices rather than the list members… but usually if you're using a list for iteration you want the actual list members.

Either way, you can skip over the first 500 just by islice:

for x, y, z, t in islice(product(list1, list2, list3, list4), 500, None):
like image 158
abarnert Avatar answered Nov 25 '25 10:11

abarnert


Since you already have a counter to keep track of your iterations, you can just use it to skip the same number of iterations until the counter reaches the previous state, while maintaining the same ranges:

counter = 0
list_of_names = []
for x in range(len(list1)):
    for y in range(len(list2)):
        for z in range(len(list3)):
            for t in range(len(list4)):
                if counter < 500:
                    continue
                Name = "A" + str(x) + " B" + str(y) + " C" + str(z) + " D" + str(t)
                list_of_names.append(Name)
                counter += 1
print(counter)
print(len(list_of_names))
like image 43
blhsing Avatar answered Nov 25 '25 10:11

blhsing