1

For the life of me I can't figure out why my IF statement is not getting hit. There are plenty of cases where the remainder of n // the last number put in the results list is 0.

n = 100
numbers = range(2, n)
results = []


results.append(numbers.pop(0))

print numbers

for n in numbers:
    if n % results[-1] == 0:
        print "If statement", numbers
        numbers.remove(n)
    else:
        print "Else statement", numbers
        numbers.remove(n)
Jared
  • 2,904
  • 6
  • 33
  • 37
  • 2
    Try adding debugging output just after the for and just after the if, e.g. `print n` `print results[-1]` – Patashu May 31 '13 at 00:11
  • 3
    You are removing items from `numbers` while iterating over it. That will lead to bugs as the iterator counter will increment regardless and your loop will 'skip' items. – Martijn Pieters May 31 '13 at 00:12
  • 2
    Calling `list.remove` causes a *side effect* on the list - what oddities may (does) this cause here? I would rewrite this *without* using remove - the opposite of removing things, is keeping those which should be kept :D It also seems odd to remove in both branches (= remove everything), but .. – user2246674 May 31 '13 at 00:17

5 Answers5

4

Problem is you're modifying the list while iterating over it, so all the even numbers are getting skipped. Hence the if condition is always False.

The for loop keeps track of index, so when you remove an item at index i, the next item at i+1th position shifts to the current index(i) and hence in the next iteration you'll actually pick the i+2th item.

for n in numbers[:]:   #iterate over a shallow copy of list
    if n % results[-1] == 0:
        print "If statement", numbers
        numbers.remove(n)
    else:
        print "Else statement", numbers
        numbers.remove(n)

Example:

>>> lis  = range(3,15)
>>> for x in lis:
...     print x
...     lis.remove(x)
...     
3
5
7
9
11
13
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
3

Don't loop over a list you are removing items from. The for loop creates a list iterator that keeps track of the current item by incrementing a counter. But a shrinking list means that the counter will, from loop iteration to loop iteration, point at the wrong item:

>>> lst = range(5)
>>> for i in lst:
...     lst.remove(i)
...     print i
... 
0
2
4
>>> lst
[1, 3]

What happens is that as you remove 0 from the list [0, 1, 2, 3, 4], the counter increments to item 1, which in the now-altered list [1, 2, 3, 4] points to the value 2. Removing 2 from the list, the iterator count increments to 2 and in the altered list [1, 3, 4] that means the next value in the loop is 4, after which the iterator counter has counted beyond the end and the loop terminates.

If you are going to remove all items from the list, use a while loop:

while numbers:
    n = numbers.pop()
    # do something with `n`

If you are removing some items, another option would be to create a shallow copy:

for n in numbers[:]:
     # ....

Now you can alter numbers to your hearts content, as the for loop is iterating over a copy instead.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
0

Another way of list modification is doing two passes:

mod0 = []
for n in numbers:
    mod0.append(n % results[-1] == 0)
print [ n for n,m in zip(numbers, mod0) if m ]
print [ n for n,m in zip(numbers, mod0) if not m ]
perreal
  • 94,503
  • 21
  • 155
  • 181
  • It seems quite useful to have a built-in method for doing it. I needed something like that many times. – Elazar May 31 '13 at 00:30
0

The problem, as others answered, is the modification of the list you are iterating on. I think what you really tried to do can be done like this:

results = [2]
numbers = []

n=100
for n in range(3, n):
    if n % results[-1] == 0:
        results.append(n)
    else:
        numbers.append(n)

which is a way to get powers of two. another way would be:

results = [2**n for n in range(1,7)]
Elazar
  • 20,415
  • 4
  • 46
  • 67
0

If you want to modify a list while looping over it, meet my little friend the while statement:

numbers=range(1,20)
while numbers:
    if numbers[-1] % 2:
        print "If statement", numbers.pop()
    else:
        print "Else statement", numbers.pop()
dawg
  • 98,345
  • 23
  • 131
  • 206