Search code examples
pythonpython-3.xmathinfinite-loop

My Python for loop loops infinitely, but only when run more than once


I'm trying to make a simple algorithm that calculates a row in a pascal triangle for you, as seen in this image.

A pascal triangle

So if I wanted to know the values of the fifth row, I just input "repeat = 5" to the program, and the program spits out "[1,5,10,10,5,1]"

And I did just that using a for loop. And it works!... If you run it once, as soon as I implement a simple for _ in range(value) the first for loop loops infinitely. I've tried using "While (condition)" and "While True" with a break, but nothing seems to work.

start = [1] #This can be any of the "steps" of the pascal triangle
secondList = []
repeat = 2  # If repeat = 1 code runs fine

for _ in range(repeat):            # Without the for loop the code runs fine (But you have to manually update start.)
    print(f"First start: {start}") # Prints [1] for the first time, then [1,1]. Then it never prints again

    for idx,i in enumerate(start):

        if idx == 0:
            j = i + 0
            secondList.append(j)

        if idx == len(start)-1:
            j = i + 0
            secondList.append(j)

        else:
            j = i + start[idx+1]
            secondList.append(j)

        print(f"End of for loop, secondList: {secondList}") # Prints [1], then [1,1], then [1,1,1,2], then [1,1,1,2,2] and so on and so forth. The for loop should run once and then twice but it runs on forever.

    start = secondList # Sets the result as the start so that it can loop as many times as instructed.

print(secondList)

Note: The code without looping works fine, say for example, I set start = [1,3,3,1](Which is row 3) and repeat = 1 then the code spits out [1,4,6,4,1] (Which is the next row, row 4)


Solution

  • Move secondList = [] into for _ in range(repeat), before for idx, i in ....

    The problem in your code actually results from start = secondList which is invoked at the end of the first iteration. Before that, start and secondList pointed to different objects. Now you are binding them to the same object.

    At the second iteration, first you didn't empty the temporary secondList. A more serious problem arises from the fact that secondList.append() also appends something to start, since they are now the same object! So each time you iterate for idx, i in enumerate(start), the list start itself grows. So this for loop can never end.

    So my remedy is to re-assign an empty list to secondList, in order to (i) re-initialize secondList and (ii) sever the link between this and start.

    start = [1]
    repeat = 5
    for _ in range(repeat):
        print(f"First start: {start}")
        secondList = []
        for idx,i in enumerate(start):
            if idx == 0:
                j = i + 0
                secondList.append(j)
            if idx == len(start)-1:
                j = i + 0
                secondList.append(j)
            else:
                j = i + start[idx+1]
                secondList.append(j)
            print(f"End of the (inner) for loop, secondList: {secondList}")
        start = secondList
    print(secondList)
    

    Output:

    First start: [1]
    End of the (inner) for loop, secondList: [1, 1]
    First start: [1, 1]
    End of the (inner) for loop, secondList: [1, 2]
    End of the (inner) for loop, secondList: [1, 2, 1]
    First start: [1, 2, 1]
    End of the (inner) for loop, secondList: [1, 3]
    End of the (inner) for loop, secondList: [1, 3, 3]
    End of the (inner) for loop, secondList: [1, 3, 3, 1]
    First start: [1, 3, 3, 1]
    End of the (inner) for loop, secondList: [1, 4]
    End of the (inner) for loop, secondList: [1, 4, 6]
    End of the (inner) for loop, secondList: [1, 4, 6, 4]
    End of the (inner) for loop, secondList: [1, 4, 6, 4, 1]
    First start: [1, 4, 6, 4, 1]
    End of the (inner) for loop, secondList: [1, 5]
    End of the (inner) for loop, secondList: [1, 5, 10]
    End of the (inner) for loop, secondList: [1, 5, 10, 10]
    End of the (inner) for loop, secondList: [1, 5, 10, 10, 5]
    End of the (inner) for loop, secondList: [1, 5, 10, 10, 5, 1]
    [1, 5, 10, 10, 5, 1]