Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is my for loop skipping an element in my list?

I have a list of integers which I am running through a for-loop to discover if the sum of two of the elements equals another variable t. So if t was equal to 10 and I had a list of integers: l = [1,2,3,4,5,8,9], then the function should print all the different combinations of numbers (1,9), (2,8).

I feel I am almost there, but something strange happens to the list when I use the .pop() function. The code below is being used to show all the combinations of numbers which need to be calculated, but every other element in the list is skipped.

l = [1,2,5,8,13,15,26,38]
c = 10
for i in l:
    first = i
    l.pop(0)
    for x in l:
        second = x
        print(first,second)

Here is the output:

1 2
1 5
1 8
1 13
1 15
1 26
1 38
5 5
5 8
5 13
5 15
5 26
5 38
13 8
13 13
13 15
13 26
13 38
26 13
26 15
26 26
26 38

Notice how the 2, 8, 15, and 38 are skipped. I am using l.pop() so that the second for-loop will not use the original value, and the next iteration can then go on to iterate the next element in the list.

like image 294
Jason Donavon Avatar asked Oct 26 '15 11:10

Jason Donavon


1 Answers

What you are trying to do will not work, as you are modifying the list while you are iterating it. Say the current "pointer" points to the first element. Now you pop the first, so the pointer is at the second. But when the loop advances, the pointer is moved to the third, and the second is skipped.

It seems you want to find combinations from a list. There are a few other ways you can try:

  • Closest to your current approach: Use a while loop instead of for loop

    while l:
        first = l.pop(0)
        for second in l:
            print(first, second)
    
  • Or you could just iterate the indices instead of the lists themselves:

    for i in range(len(l)):
        for k in range(i+1, len(l)):
            print(l[i], l[k])
    
  • Or just use itertools.combinations

    import itertools
    for first, second in itertools.combinations(l, 2):
        print(first, second)
    

However, you can do better than that. Since you are looking for a pair of numbers that adds up to some target number, just subtract the first from the target to get the second and see if that second number is in the list of numbers. Use a set to make this lookup happen in constant time, reducing your overall time complexity from O(n²) to O(n).

numbers = set([1,2,5,8,13,15,26,38])
target = 10
for first in numbers:
    second = target - first
    if second > first and second in numbers:
        print(first, second)
like image 145
tobias_k Avatar answered Oct 16 '22 19:10

tobias_k