问题
i wrote a program to evaluate what numbers in a certain range are divisble by only certain numbers (in the range 1
to 9
). So far the code seems to work but i tested the steps it takes through at pythontutor http://www.pythontutor.com/visualize.html#mode=edit and something odd happened.
In the second loop, the code doesnt always check all values (k)
for its divisibility but sometimes leaves out the last value (k)
.
Better to give you an example:
Liste = []
for i in range (1500, 1700):
if i%5 == 0 and i%7 == 0:
Liste.append(i)
print (Liste)
Teiler = [2, 3, 4, 6, 8, 9]
for k in Liste:
z = 0
for w in range (len(Teiler)):
if k%Teiler[z] == 0:
Liste.remove(k)
z += 1
break
else:
z += 1
print (Liste)
Here the output is as follows:
[1505, 1540, 1575, 1610, 1645, 1680]
[1505, 1575, 1645]
And its the output that its supposed to be, as in the second list are only the numbers divisible by 5
and 7
. Also on pythontutor the second for loop goes through all values (k)
.
But when i change the range of number like the following (line 2, change range from 1700
to 1800
):
Liste = []
for i in range (1500, 1800):
if i%5 == 0 and i%7 == 0:
Liste.append(i)
print (Liste)
Teiler = [2, 3, 4, 6, 8, 9]
for k in Liste:
z = 0
for w in range (len(Teiler)):
if k%Teiler[z] == 0:
Liste.remove(k)
z += 1
break
else:
z += 1
print (Liste)
the output is as the following:
[1505, 1540, 1575, 1610, 1645, 1680, 1715, 1750, 1785]
[1505, 1575, 1645, 1715, 1785]
If i run this code on pythontutor, the code stops at k = 1750
and doesnt check for k = 1785
.
Why is it behaving that way? Is it a problem with the check on pythontutor? Or is there a problem with my code?
I want to understand why Python is doing what it does.
Thank you very much for your help. Iam sorry if this is a noob question or iam missing out something obvious.
回答1:
Don't remove items from the list you iterate over, as the other answer states. Changing the length of the list affects the iteration. Example:
>>> L=list(range(10))
>>> for i in L:
... if i==5: L.remove(i)
... print(i)
...
0
1
2
3
4
5 # removed 5, and skipped 6!
7
8
9
Also w
is never used, although z
is the equivalent. Instead, iterate directly over Teiler
and add items to a new list if it satisfies your condition:
Liste = []
for i in range (1500, 1800):
if i%5 == 0 and i%7 == 0:
Liste.append(i)
print (Liste)
Liste2 = []
Teiler = [2, 3, 4, 6, 8, 9]
for k in Liste:
for w in Teiler:
if k % w == 0:
break
else:
Liste2.append(k)
print(Liste2)
Output:
[1505, 1645, 1715]
If you haven't seen for/else
, the else
only executes if you don't break from the for
loop, so all of k % w != 0
has to be true.
Another option is to use list comprehensions, which really simplify the code:
L = [i for i in range(1500,1800) if i%5 == 0 and i%7 == 0]
L = [x for x in L if all(x % k != 0 for k in (2,3,4,6,8,9))]
print(L)
Output:
[1505, 1645, 1715]
Note 1575 and 1785 are divisible by 3, so both your sample lists had errors from removing values in the list.
回答2:
Your problem is in this line:
Liste.remove(k)
because you are removing element from the same list that you use for the for loop so when you delete an element the list is going to be shorter but next iteration you will jump an element.
I advice to use two list or use a while loop and when you remove the element from list you don't go to next iteration and you decrease the len of the list of 1; example:
Liste = []
for i in range (1500, 1800):
if i%5 == 0 and i%7 == 0:
Liste.append(i)
print (Liste)
Teiler = [2, 3, 4, 6, 8, 9]
l=len(Liste)
i=0
while i<l:
k=Liste[i]
z = 0
for w in range (len(Teiler)):
if k%Teiler[z] == 0:
Liste.remove(k)
l-=1
i-=1
z += 1
break
else:
z += 1
i+=1
This code could be improved but was for let you understand how you can do it
来源:https://stackoverflow.com/questions/53064481/loop-through-numbers-and-evaluate-if-numbers-are-divisible-by-certain-numbers