2010-11-26 5 views
1

リストをフィルタリングしようとしています。ここにコードがあります。フィルタリング時に予期せぬ出力が出るPython list:どうしたのですか?

 test=['aaa','bbb','ccc','ddd','footer','header'] 

def rm_hf(x): return x != 'footer' 

filter(rm_hf,test) 

結果:

>>>['aaa','bbb','ccc','ddd','header'] 

これは、リスト内の「フッター」を見つけて削除すると予想されます。

今、私は「ヘッダ」と「フッター」の両方を削除したいので、私はこれを行う:中

 test2=['aaa','bbb','ccc','ddd','footer','header'] 

def rm_hf2(x): return x != 'footer' or x != 'header' 

filter(rm_hf2,test2) 

結果:

>>>['aaa','bbb','ccc','ddd','footer','header'] 

は今、それはそれは単に「フッターの両方を与え、奇妙な'、'ヘッダー 'をフィルタリングする代わりに使用しますか?

どうしたのですか?私の論理は正しいと思う...

+4

と、いないか!!!!! –

+3

-1: "奇妙な振る舞い"と "Pythonのバグ"と混同された単純な論理質問。それは常に論理です。 'rm_hf2'をテストするのはどれくらい難しいですか? –

+0

まあ、私はちょうど質問をはっきりと尋ねました、あなたは私を訂正するのではなく、私を投票しました。私は笑いを止めることはできません。私は投票をどうにかしていますので、投票してください:) –

答えて

7

あなたは人間のように思えるので、あなたのロジックは正しいです。あなたのコンピュータはそうではありません。彼はあなたのリストからすべての要素を読んでから、「フッター」を見つけます。 「フッタはフッタと異なるのですか?」と彼は言います。 "いいえ、それは同じ文字列です!偽に評価されます。次の条件を見てみましょう"。 「フッターとヘッダーとは異なるのですか?はい!従って、条件はFalse or Trueであり、明らかに真であると評価される。

あなたはand、ないorをしたい:

def rm_hf2(x): return x != 'footer' and x != 'header' 

あなたはまた、タプル、より読みやすいinキーワード、使用することができます:それはあなたが本当に何を理解することが重要です

def rm_hf2(x): return x not in ('footer', 'header') 

を"and"と "and"のいずれかになります。そして、正直なところを言いましょう。何かがうまくいかないと思ったときに、問題はPython言語自体ではなく、あなた自身のコードにある可能性が高いです。

あなたは除外したいいくつかのアイテムを持っている場合は、代わりにand秒の鎖またはtupleset使用:

# do once 
blacklist = set(['header', 'footer']) 

# as needed 
filter(lambda x: x not in blacklist, some_iterable) 

理論的根拠:探していると述べ、プラス何他のみんな

+1

論理エラーの別の説明です:彼は 'not(x == 'footer'やx == 'header')'を書いたと思っていましたが、 '(not x == 'footer')または(x == 'header') 'ではありません。 –

+0

@ THC4k:「初心者の間違い」は、「それらのどれであってはいけない」という意味で「または」と書くことは可能ですが、可能です。 –

+1

別の説明:彼は、彼が書いたフィルタ関数を読まなかった。INCLUSIVE_OR彼は彼が書いたフィルタ関数をテストしなかった。 –

2

tupleまでは、見つかった項目の位置に比例した時間がかかります。失敗は最後の項目と同じ時間になります。セット内のアイテムをルックアップすることは、すべてのアイテムおよび失敗に対して同じ時間を要する。通常、セットは多数のアイテムに勝ちます。それはすべて、各アイテムが検索される確率、および失敗の確率に依存します。タプルは、いくつかのアイテム(タプルの前に置く必要があります)の確率が高く、失敗の可能性が低いときに大きなコレクションでも勝てます。

+0

ありがとう、セットvsタプルを使用する利点? –

+1

@ V3ss0n:私の編集した答えを見てください。 –

+0

ありがとうございました。リストの理解度を比較するとリストを使用しました。私はセットに変更する必要があります。これらのリストは大きく、20k個のアイテムを持つファイルのリストです。 –

1

フィルタの代わりにリストの理解を使用することもできます。

test = ['aaa','bbb','ccc','ddd','footer','header'] 
filtered_test = [x for x in test if x not in ('footer', 'header')] 

やジェネレータ式(ニーズに応じて)

test = ['aaa','bbb','ccc','ddd','footer','header'] 
filtered_test = (x for x in test if x not in ('footer', 'header')) 
+0

はい、私はちょうどリスト内包を使用しました。しかし、思考フィルタは読みやすく、私はフィルタを疲れ、それは初めてフィルタを使用しています。私は通常、フィルタやマップを使用しないで、内容をリストにします。 –

+1

@ V3ss0nこれは、理解しやすいものです。なぜなら、読みやすく理解しやすいからです。 – fmark

4

my logic is correct

他の回答で強調されているように実際には、いや、それは、ないです。

望ましい結果を達成するためにはるかに滑らかな印象の方法は VIZ list comprehensionsを使用することです:

test = ['aaa', 'bbb', 'ccc', 'ddd', 'footer', 'header'] 
undesirable = ['footer', 'header'] 
[_ for _ in test if _ not in undesirable] 

the documentationから:

Note that filter(function, iterable) is equivalent to [item for item in iterable if function(item)] if function is not None and [item for item in iterable if item] if function is None .

磨くために現在のようなもう時間がありません、と述べましたあなたのBoolean logicのアップ!

コードを単体テストしていたら、2番目のフィルタ機能が期待したことをしていないことがすぐにわかります。ここで簡単な例である:

$ cat 4281875.py 
#!/usr/bin/env python 

import unittest 

def rm_hf2(x): return x != 'footer' or x != 'header' 

class test_rm_hft(unittest.TestCase): 

    def test_aaa_is_not_filtered(self): 
     self.assertTrue(rm_hf2('aaa')) 

    def test_footer_is_filtered_out(self): 
     self.assertFalse(rm_hf2('footer')) 


if __name__ == '__main__': 
    unittest.main() 


$ ./4281875.py 
.F 
====================================================================== 
FAIL: test_footer_is_filtered_out (__main__.test_rm_hft) 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "./4281875.py", line 13, in test_footer_is_filtered_out 
    self.assertFalse(rm_hf2('footer')) 
AssertionError 

---------------------------------------------------------------------- 
Ran 2 tests in 0.000s 

FAILED (failures=1) 
関連する問題