2012-03-13 17 views
3

解決策はおそらく単純ですが、わかりません。ここにコードがありますが、これは簡単なフィボナッチ数生成器です。目標は、フィボナッチ数が4,000,000以下であってもすべて合算することです。Python:モジュロ演算子での奇妙な振る舞い

私のアプローチは、最初の4,000,000の下にすべてのフィボナッチ数を生成することで、その後、次のいずれか は、A)から、奇妙なものを削除する(これは正常に動作します) b)は「偶数」)も、ものと(新しいリストを生成しますリスト "すべて"

しかし、後者の場合、出力は理解できない理由のため次のようになります。 [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

+0

DSM、これを指摘してくれてありがとう! – talkinghead

+0

フィボナッチシーケンスについて誰かが驚いた場合:はい、通常、0,1,1,2、...で始まりますが、この問題のProject Eulerの指示では、1,2、... 2で始まります。 – talkinghead

答えて

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 all for x%2 == 0]'。 – delnan

+0

ええ、リストの理解は良く見えます。コードを自分で書いたのなら、おそらくそれを書くでしょう。あなたが答えとしてそれを書いたら、私はそれを投票するだろう!しかし、私は通常、自分の答えが質問者にとってより有用であることが分かります。私のSOスタイルは質問に対して最小限の相違点を設けて正しく動作させることです。 – mattbornski

+0

マット、 ありがとうございます。また、Delnanのソリューションよりもはるかに簡単に元のコードに変更を加えることができます。 Delnanのコードは、熟練したPython開発者にとってはより明確になるかもしれませんが、それは私にとってはやや簡潔です。私はメモを作った。数ヶ月で、私もそれを好むかもしれません... – talkinghead

-1

これは、インデックスiの項目を数字「i」で削除しているためです。

+3

私はそれが本当だとは思わない。 'python 2.7.2(デフォルト、2011年11月14日、19:37:59) ダーウィンの[GCC 4.2.1(アップル社のビルド5666)(ドット3)] " help "、" copyright "、" credits詳細については、「ライセンス」を参照してください。 >>> FOO = [5、4、3、2、1] >>> foo.remove(5) >>> FOO [4、3、2、1] ' – mattbornski

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] 

ここで、Pythonが起動するとリストを反復、それは技術的に...それが反復するために持っているから、数の位置だけを覚えて

我々は最初の反復では、出力、

を観察した場合、それは1.

を削除します次の反復で、それは第2の位置を数えなければならないことを記憶する。今度はリストが "2"から始まります。したがって、2番目の位置は「3」です。したがって、それはそれを削除します。

次の反復では、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.