2010-11-26 5 views
1

Ich versuche, eine Liste zu filtern, hier ist der Code:Unerwartete Ausgabe beim Filtern der Python-Liste: Was mache ich falsch?

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

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

filter(rm_hf,test) 

Ergebnisse in:

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

Das Ergebnis erwartet wird, 'Footer' in der Liste zu finden und zu entfernen.

Jetzt möchte ich beide 'header' und 'footer' entfernen, so kann ich dies tun:

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

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

filter(rm_hf2,test2) 

Ergebnisse in:

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

Nun seltsam das ist, es gibt nur gerettet ‚Fußzeile ',' header 'anstatt sie zu filtern?

Was habe ich falsch gemacht? Ich denke meine Logik ist korrekt ...

+4

und, nicht oder !!!!! –

+3

-1: Trivial Logik Frage mit "seltsames Verhalten" und "Bug in Python" verdüstert. Es ist immer logisch. Wie schwer kann es sein, 'rm_hf2' zu testen? –

+0

Nun, ich habe nur die Frage klar gestellt, Sie stimmen mich einfach ab, anstatt mich zu korrigieren, wow, was für ein Experte LOL. Ich kann nicht aufhören zu lachen. Nun, ich sorge mich nicht, dass die Abstimmungen hier sind, also genießt es, mich zu wählen :) –

Antwort

7

Ihre Logik ist richtig, weil Sie wie ein Mensch denken. Dein Computer tut es nicht. Er liest jedes Element aus Ihrer Liste und stolpert dann auf "Fußzeile". "Ist Fußzeile anders als Fußzeile?", Sagt er. "NEIN! Es ist die gleiche Zeichenfolge! Es ist zu falsch ausgewertet. Lassen Sie uns die nächste Bedingung sehen". "Ist Fußzeile anders als Kopfzeile? JA!" Die Bedingung lautet daher False or True, was offensichtlich zu wahr ist.

Sie wollen ein and, kein or:

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

Sie auch ein Tupel und das in Schlüsselwort verwenden könnte, die besser lesbar ist:

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

Es ist wichtig, dass Sie verstehen, was wirklich weiter mit "und" und "oder", obwohl. Und seien wir ehrlich: Wenn etwas nicht so funktioniert, wie Sie es für richtig halten, liegt das Problem höchstwahrscheinlich in Ihrem eigenen Code und nicht in der Python-Sprache selbst.

+1

Hier ist eine weitere Erklärung für den logischen Fehler: Er dachte, er schrieb 'nicht (x == 'footer' oder x == 'header')' aber schrieb '(nicht x == 'Fußzeile') oder (nicht x == 'Kopfzeile') 'statt. –

+0

@ THC4k: Es ist möglich, obwohl es ein gewöhnlicher Anfängerfehler ist, "oder" zu schreiben, wenn du meinst "sollte keiner von denen sein". –

+1

Eine andere Erklärung: Er hat die Filterfunktion, die er geschrieben hat, nicht gelesen. INCLUSIVE_OR hat die von ihm geschriebene Filterfunktion nicht getestet. –

2

Was für alle sagten sonst plus:

Wenn Sie einige Einzelteile haben, die Sie ausschließen möchten, eine set statt einer Kette von and s verwenden oder ein tuple:

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

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

Begründung: Auf der Suche durch eine tuple dauert Zeit proportional zur Position des gefundenen Artikels; Fehler dauert die gleiche Zeit wie der letzte Artikel. Das Nachschlagen eines Gegenstands in einem Satz dauert für alle Gegenstände und für einen Fehler dieselbe Zeit. Sätze gewinnen normalerweise für eine große Anzahl von Gegenständen. Es hängt alles von der Wahrscheinlichkeit ab, dass jeder Gegenstand durchsucht wird, und von der Wahrscheinlichkeit des Versagens. Tupel können sogar mit einer großen Sammlung gewinnen, wenn die Wahrscheinlichkeit hoch ist, dass einige Items (sie sollten an der Spitze des Tupels stehen) und die Wahrscheinlichkeit, dass sie ausfallen, gering ist.

+0

danke, jeder Vorteil der Verwendung von Sets vs Tupel? –

+1

@ V3ss0n: siehe meine bearbeitete Antwort. –

+0

Vielen Dank. Ich habe Listen verwendet, um Listenverstehen zu vergleichen. Ich sollte zu Sets wechseln. Diese Liste ist groß, sie sind eine Liste von Dateien, die 20k + Elemente haben. –

1

Sie können auch ein Listenverständnis statt Filter verwenden.

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

oder ein Generator Ausdruck (je nach Bedarf)

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

Ja, ich habe gerade Listenübersichten verwendet. Aber Gedankenfilter ist besser lesbar, und ich müde Filter, es ist das erste Mal mit Filter. , ich benutze normalerweise keine Filter oder Karten, listen nur die Comprehensions auf –

+1

@ V3ss0n Aus diesem Grund solltest du bei den Comprehensions bleiben - gerade weil sie einfacher zu lesen und zu verstehen sind! – fmark

4

my logic is correct

Eigentlich nein, es ist nicht, wie in anderen Antworten hervorgehoben.

Eine weit übersichtlicher Art und Weise das gewünschte Ergebnis zu erreichen, ist list comprehensions zu verwenden, nämlich:

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

Von 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 .

Das heißt, es gibt keine Zeit wie die Gegenwart zu bürsten -up auf Ihrem Boolean logic!

Wenn Sie Ihren Code testen würden, würden Sie schnell herausfinden, dass Ihre zweite Filterfunktion nicht das tut, was Sie erwarten. Hier ein einfaches Beispiel:

$ 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)