0

Im trying to pass a list of numbers to a primality function. What I expect is for it to return the items that are primes and discard those that arent.

Here is the code:

def primality(num):
    if num % 2 == 0 and num > 2:
        return False
    return all(num % i for i in range(3, int(math.sqrt(num)) + 1, 2))

Does not work, why?

nums = [31, 71, 91, 32, 92, 13, 73, 14, 34, 74]
for i, s in enumerate(nums):
    if not primality(nums[i]):
        del nums[i]
print(nums) # it prints [31, 71, 32, 13, 73, 34] which is wrong, 32 and 34 shouldnt be there

But this works:

temp = []
for i, s in enumerate(nums):
    if not primality(nums[i]):
        continue
    temp.append(s)
print(temp) # [31, 71, 13, 73] which is correct

My question is very basic, but I cant figure out why the first method of removing items from the existing list doesn't remove all non-primes? what am I doing wrong?

Joe Sebin
  • 452
  • 4
  • 24
  • 4
    Possible duplicate of [How to remove items from a list while iterating?](https://stackoverflow.com/questions/1207406/how-to-remove-items-from-a-list-while-iterating) – Thierry Lathuille May 25 '18 at 10:07

3 Answers3

0

Removing item while iterating over it leads to this kind of errors.

One approach here could be to create a new list with the constraint you choose:

nums = [31, 71, 91, 32, 92, 13, 73, 14, 34, 74]
prims = [n for n in nums if primality(n)]
# returns : [31, 71, 13, 73]
Antwane
  • 20,760
  • 7
  • 51
  • 84
0

I explain you what is performed on each iteration of the for loop of your original code:

  • Iteration 1 : i = 0, s = 31 : nums is unchanged
  • Iteration 2 : i = 1, s = 71 : nums is unchanged
  • Iteration 3 : i = 2, s = 91 : nums is changed
    ==> "91" is removed and so next elements are left-shifted
    ==> nums = [31, 71, 32, 92, 13, 73, 14, 34, 74]
  • Iteration 4 : i = 3, s = 92 : nums is changed
    ==> "92" is removed and so next elements are left-shifted
    ==> nums = [31, 71, 32, 13, 73, 14, 34, 74]
  • Iteration 5 : i = 4, s = 73 : nums is unchanged
  • Iteration 6 : i = 5, s = 14 : nums is changed
    ==> "14" is removed and so next elements are left-shifted
    ==> nums = [31, 71, 32, 13, 73, 34, 74]
  • Iteration 7 : i = 6, s = 74 : nums is changed
    ==> "74" is removed
    ==> nums = [31, 71, 32, 13, 73, 34]

So finally you have: nums = [31, 71, 32, 13, 73, 34]

Conclusion: "Do not modify an object while iterating over it" would be the good take-home message.

Laurent H.
  • 6,316
  • 1
  • 18
  • 40
  • Oh ok! I get it now! 32 gets skipped because it gets left shifted to the third spot when 91 is removed and we've already iterated over the 3rd spot. Thanks for explaining it so well. – KabirGandhiok May 25 '18 at 10:27
-1

In the loop len(nums) is changing! So the pointer i is not corect. After the first and the second loup of for the nums[] is the same. The therd time nums[] is changed becouse nums[2] 91 is deleted! Now nums[3] is not 32 but is 92 and 92 is deleten instent 32 you exept.

nums = [31, 71, 91, 32, 92, 13, 73, 14, 34, 74] // del i[2] = 91
nums = [31, 71, 32, 92, 13, 73, 14, 34, 74]     // del i[3] = 92
nums = [31, 71, 32, 13, 73, 14, 34, 74]         // del i[4] = 73 
nums = [31, 71, 32, 13, 73, 14, 34, 74]
Manos Gero
  • 31
  • 5