Muhammed Eltabakh
Muhammed Eltabakh

Reputation: 497

How to break and start from where I ended in a nested loop

I want to run this loop over a list basically it searches for a number in my a range till it finds it search for the next number in the following iterations but instead it starts over again

This is my code

z = [30,84,126,135,137,179,242,342,426]
c=[]
for m in z:
    for i in range(1,1002, 7):
        if m  in range(i, i+7):
            c.append(m%7)
            break
        elif m not in range(i, i+7):
            c.append(0)
print len(c) # outputs 246 

but len(c) should be equal to 143, how do I fix this?

Upvotes: 0

Views: 101

Answers (3)

f5r5e5d
f5r5e5d

Reputation: 3706

while a generator seemed to answer the question, there is a better tool for the programming problem: itertools.groupby

from itertools import groupby


z = [1,2,3, 30,84,126,135,136,137,140,141,179,242,342,426]

g = dict([[k, [*g]] for k, g in groupby(z, key=lambda x: (x-1)//7)])

d = [((tuple(g[i]) if len(g[i]) > 1 else g[i][0]) if (i in g) else 0)
     for i in range(0, 143)]

ran against my 1st answer's code: (do use the same z, it has been changed)

c == d
Out[278]: True

see how well matched itertools.groupby is look at the dict wrapped groupby result:

g
Out[279]: 
{0: [1, 2, 3],
 4: [30],
 11: [84],
 17: [126],
 19: [135, 136, 137, 140],
 20: [141],
 25: [179],
 34: [242],
 48: [342],
 60: [426]}

(the above works in 3.6, the [*g] and dictionary key test (i in g) may be different in 2.7)

Upvotes: 1

f5r5e5d
f5r5e5d

Reputation: 3706

perhaps what you want is a generator https://docs.python.org/2/howto/functional.html#generator-expressions-and-list-comprehensions

z = [30,84,126,135,136,137,179,242,342,426]
c = []


def counter(maximum, inc):  # resetable generator from doc example
    i = 1
    while i < maximum:
        val = (yield i)
        # If value provided, change counter
        if val is not None:
            i = val
        else:
            i += inc


ig = counter(1002, 7)

for m in z:
    for i in ig:
        # catch multiple nums in same range
        if m < i:
            clast = c.pop()
            # inline if-else inside append converts int to tuple to add m to
            c.append((clast if type(clast) == tuple else (clast,)) + (m,))
            # reset ig count
            ig.send(i - 7)
            break

        if i <= m < i+7:
            c.append(m)
            break
        else:
            c.append(0)
# exhaust ig if you really want full count = 143
for i in ig:
    c.append(0)

print(len(c)) 

added catching nums in same interval, needed the resettable generator

fixed up the last 2 issues I know of: now makes a flat tuple for multiple nums in a single range counts correctly by resetting ig to i - 7

Upvotes: 1

ividito
ividito

Reputation: 336

I think I figured out what you're trying to do, and your best bet is to change how you're incrementing your search range.

z = [30,84,126,135,137,179,242,342,426]
c=[] # initialize results array
i = 1 # initialize i
for m in z: # for each item in list
    while 1: # perform this action until loop breaks
        if m in range(i, i+7): #if m is in range
            c.append(m%7)
            break #break the while loop, moving on to the next item
        elif m not in range(i, i+7):
            c.append(0) 
            i = i+7 #increment the search range, but do not break the loop

#Display results
print len(c)
print c

So in your original code, you reset the search range i for each element in the array z. This is why your len(c) values are getting so much higher than expected. In my code, I only iterate i from 1 to 1002 a single time as I go through the array of values.

Please let me know if this doesn't solve your issue, I was able to match the functionality you described but not the expected output for len(c). If you want to get the expected value, you can change the code to match this:

z = [30,84,126,135,137,179,242,342,426]
c=[] # initialize results array
i = 1 # initialize i
for m in z: # for each item in list
    while i<1002: # perform this action until loop breaks
        if m in range(i, i+7): #if m is in range
            c.append(m%7)
            i = i+7
            break # break the while loop, moving on to the next item
        elif m in range(i-7, i):
            break
        else:
            c.append(0) 
            i = i+7 # increment the search range, but do not break the loop

while i<1002: # finish iterating i all the way up to 1002
    c.append(0) 
    i = i+7


#Display results
print len(c)
print c

Which gets a len(c) of 143.

Upvotes: 1

Related Questions