2012-03-13 27 views
3

該解決方案可能相當簡單,但我無法弄清楚。這是代碼,它是一個簡單的斐波那契數字生成器。目標是總結所有甚至低於4,000,000的斐波納契數。Python:與模運算符的奇行爲

我的做法是,先產生低於400萬的所有Fibonacci數,然後或者: 一)產生一個新的列表(「偶」)與甚至是那些(這工作正常) b)除去從奇數的人list「all」

但是,在後一種情況下,出於我不明白的原因,這: [2,5,8,21,34,89,144,377,610,1597 ,2584,6765,10946,28657,46368,121393,196418,514229,832040,2178309,3524578]

任何幫助,非常感謝。謝謝!

all = [] 
even = [] 

def fibonacci(): 
    a, b = 1, 2 
    while a < 4000000: 
     all.append(a) 
     a, b = b, a + b 
    print all 

##Putting all the even fibonacci numbers in a different list and summing them up works fine 
# for i in all: 
#  if i % 2 == 0: 
#   even.append(i) 
# print even     
# print sum(even) 


# But for some strange reason I can't figure out how to remove the odd numbers from the list 
    for i in all: 
     if i % 2 != 0: 
      all.remove(i) 

    print all 
    print sum(all) 

fibonacci() 
+0

我建議你不要使用「全部」作爲變量名。有一個非常有用的內建函數叫做[all](http://docs.python.org/library/functions.html#all),它非常方便。 – DSM 2012-03-13 19:35:39

+0

帝斯曼,感謝您指出這一點! – talkinghead 2012-03-13 20:52:48

+0

此外,如果有人對斐波納契序列有所瞭解:是的,它通常以0,1,1,2,...開頭,但是對於這個問題的歐拉項目說明書已經以1,2,..., – talkinghead 2012-03-13 21:00:34

回答

4

這是一個「疑難雜症」情況:您在迭代列表時從列表中刪除項目,從而更改列表,導致您的迭代意外行爲。試試這個:

... 
# But for some strange reason I can't figure out how to remove the odd numbers from the list 
    for i in all[:]: 
     if i % 2 != 0: 
      all.remove(i) 
... 

這是所謂的「切片」符號,並且使你遍歷列表的一次性副本,以便您的迭代不會受到all.remove()調用。

+3

另一種解決方案是更多簡潔,可以說更加清晰,至少有效(當你複製整個列表)過濾產生一個新列表:'all = [x for x in all if x%2 == 0]'。 – delnan 2012-03-13 17:38:14

+0

是的,列表理解看起來不錯,如果我自己編寫代碼,我可能會這樣寫。如果你把它寫成答案,我會把它投票!然而,我通常會發現,我的答案對提問者來說更接近他們更類似於問題的方式,所以我的SO風格是對問題做出最小差異,以使其行爲正確。 – mattbornski 2012-03-13 17:42:07

+0

亞光, 非常感謝您的解釋。另外,我確實發現你對我的原始代碼的修改比delnan的解決方案更容易理解。儘管對於一位經驗豐富的Python開發人員,delnan的代碼可能更加清晰,但對我來說這太簡單了。我已經做了一個筆記。在幾個月內,我可能更喜歡它...... – talkinghead 2012-03-13 20:55:33

-1

這是因爲您刪除索引i處的項目而不是數字「i」。

+3

我不相信這是真的。 'Python 2.7.2(default,2011年11月14日,19:37:59) [GCC 4.2.1(Apple Inc. build 5666)(dot 3)] darwin 輸入「help」,「copyright」,「credits 「或」許可證「以獲取更多信息。 >>> foo = [5,4,3,2,1] >>> foo.remove(5) >>> foo [4,3,2,1] ' – mattbornski 2012-03-13 17:34:45

3

您無法從迭代的列表中刪除項目。 Python使用迭代器,它只知道相對於列表開始的當前索引。當您從列表的前面刪除項目時,所有元素的位置都會更改,並跳過下一個元素。

可避免很多方面的問題,例如與發電機:

def fibonacci(): 
    a, b = 1, 2 
    while a < 4000000: 
     yield a 
     a, b = b, a + b 

def even(seq): 
    for item in seq: 
     if item % 2 == 0: 
      yield item 

print sum(even(fibonacci())) 
0

如果我們仔細觀察迭代下面的代碼是如何發生的

for i in all: 
     if i % 2 != 0: 
      all.remove(i) 

      # Add these two lines for debugging.. 
      # Or to know how this iteration functions 

      print "when %d: " %i 
      print all 

    print "Remaining Evens", 
    print all 

這是輸出會怎樣看起來,如果最大數量是100

original series [1, 2, 3, 5, 8, 13, 21, 34, 55, 89] 
when 1: 
[2, 3, 5, 8, 13, 21, 34, 55, 89] 
when 3: 
[2, 5, 8, 13, 21, 34, 55, 89] 
when 13: 
[2, 5, 8, 21, 34, 55, 89] 
when 55: 
[2, 5, 8, 21, 34, 89] 
Remaining Evens [2, 5, 8, 21, 34, 89] 

這裏蟒開始時迭代一個列表,在技術上只記得從它具有迭代次數的位置..

如果我們觀察輸出,

在第一次迭代,它消除1.

在下一次迭代時,它會記住它必須計算第二個位置。現在列表從「2」開始。所以第二個位置是「3」。因此它將其刪除。

在下一次迭代中,它記得它必須從第3個位置開始計數。現在在當前列表中,第三位是「8」。所以,它從那裏計數..不是從「5」。所以,由於8不滿足,它會到13 ..

因此,它跳過所有這些數字..

如何解決這個問題:

其實,你需要做的「所有」名單和迭代的副本。 (它不應該指向同一個對象..)。如果是這樣,同樣的事情發生。

你能做到這一點,只需使用切片運算符:

copy_all= all[:] 

#or else, you need to use deepcopy() 

import copy 
copy_all = copy.deepcopy(all) 

# you iterate copy_all but delete in all. 

However, prefer the first method. Its very simple.