2

測定デバイスの負の数やエラーなどのアーティファクトを取り除くために、使用しているデータをフィルタリングしようとしています。これを行うためにジェネレーターを使用するというアイデアで遊んでいます。私はPython 2.7.2を使用しています

testlist = [12,2,1,1,1,0,-3,-3,-1]  

gen = (i for i, x in enumerate(testlist) if x < 0 or x > 2.5)

for i in gen: testlist.pop(i)

print testlist

これは以下を返します:

[2, 1, 1, 1, 0, -3]

私の質問は、更新された「テストリスト」に -3 の値が表示されるのはなぜですか?

4

4 に答える 4

7

リストからアイテムを削除すると、その後のアイテムのインデックスが変更されます (すべて 1 つ下にシフトされます)。その結果、ジェネレーターはいくつかの項目をスキップします。何が起こっているかを確認できるように、いくつかの print ステートメントを追加してみてください。

for i in gen:
        print i
        print testlist
        testlist.pop(i)

出力:

0
[12, 2, 1, 1, 1, 0, -3, -3, -1]
5
[2, 1, 1, 1, 0, -3, -3, -1]
6
[2, 1, 1, 1, 0, -3, -1]

インデックス 0、5、5、5 の項目を削除する必要がありました。ジェネレーターはインデックス 0、5、6 を生成します。これは理にかなっています。などをenumerate返すため0, 1, 2, ...です。同じインデックスを連続して 2 回返すことはありません。

また、一度に 1 つずつ要素を削除するのは非常に非効率的です。これには、データを複数回移動する必要があり、最悪の場合のパフォーマンスは O(n 2 ) です。代わりにリスト内包表記を使用できます。

testlist = [x for x in testlist if 0 <= x <= 2.5]
于 2012-06-06T20:38:17.763 に答える
1

これを行うためのより良い方法は、リスト内包を使用して新しいフィルターされたリストを作成することです。

testlist = [12,2,1,1,1,0,-3,-3,-1]  

testlist[:] = [x for x in testlist if 0 <= x <= 2.5]

与える:

[2, 1, 1, 1, 0]
于 2012-06-06T20:51:58.920 に答える
1

より単純な入力を考えてみましょう:

[-3, -4, -5]

最初に (0, -3) が列挙子から取得されます。ジェネレーターに 0 が追加されます。for ループは、新しい要素がジェネレーターから利用可能であることを通知し、-3 を削除します。

[-4, -5]

列挙子から新しい要素を取得します。列挙子は最初の要素を取得したことを記憶しているため、2 番目の要素 (-5) を取得します。-5 も同様にリストから削除されます。-4のままです。

ちなみに、あなたがしようとしていることをより簡単に行う方法は次のとおりです。

testlist = filter(lambda x: x >= 0 and x <= 2.5, testlist)
于 2012-06-06T20:41:31.727 に答える
1

作業中のリストを変更しています。これは、他の言語でループから for ループなどのインデックス値を変更するのと似ています。別の方法として、次のアプローチを検討してください。

testlist = [x for x in testlist if x >= 0 and x <= 2.5]

リスト内包表記を使用すると、ジェネレーター式ではありませんが、より直接的に機能するはずですが、簡単に1つに変更できます。

testlist = (x for x in testlist if x >= 0 and x <= 2.5)
于 2012-06-06T20:39:03.597 に答える