2010-11-26 4 views
1

Je suis en train de filtrer une liste, voici le code:Sortie inattendue lors du filtrage de la liste Python: Que fais-je de mal?

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

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

filter(rm_hf,test) 

Résultats dans:

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

C'est le résultat attendu, trouver « pied » dans la liste et le retirer.

Maintenant, je veux supprimer à la fois « en-tête » et « bas de page », donc je le fais:

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

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

filter(rm_hf2,test2) 

Résultats dans:

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

Maintenant qui est bizarre, il donne juste à la fois « pied de page ',' header 'au lieu de les filtrer?

Qu'est-ce que j'ai fait de mal? Je pense que ma logique est correcte ...

+4

et, pas ou !!!!! –

+3

-1: Question de logique triviale embrouillée avec "comportement étrange" et "bug en Python". C'est toujours logique. Comment peut-il être difficile de tester 'rm_hf2'? –

+0

Eh bien, je viens de poser une question clairement, vous venez de me voter au lieu de me corriger, wow, ce qu'un expert LOL. Je ne peux pas m'arrêter de rire.Bien je ne me soucie pas des votes ici de toute façon, alors profitez-moi de me voter :) –

Répondre

7

Votre logique est correcte parce que vous pensez comme un humain. Votre ordinateur ne le fait pas. Il lit chaque élément de votre liste, puis trébuche sur «pied de page». "Le footer est-il différent du footer?", Dit-il. "NON, c'est la même chaîne, elle est évaluée à false, voyons la condition suivante". "Le pied de page est-il différent de l'en-tête?" La condition est donc False or True, ce qui évalue évidemment à vrai.

Vous voulez un and, pas or:

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

Vous pouvez également utiliser un tuple et le mot-clé in, qui est plus lisible:

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

Il est important que vous compreniez ce qui est vraiment continuer avec "et" et "ou", cependant. Et soyons honnêtes: si quelque chose ne fonctionne pas comme vous le pensez, le problème réside probablement dans votre propre code, et pas dans le langage Python lui-même.

+1

Voici une autre explication de l'erreur logique: Il pensait qu'il écrivait 'non (x == 'footer' ou x == 'en-tête')' mais écrivait '(pas x == 'footer') ou (pas x == 'en-tête') 'à la place. –

+0

@ THC4k: C'est possible, même si c'est une erreur débutante courante d'écrire 'ou 'quand vous voulez dire" ne devrait pas être un de ceux-là ". –

+1

Une autre explication: Il n'a pas lu la fonction de filtre qu'il a écrit INCLUSIVE_OR qu'il n'a pas testé la fonction de filtre qu'il a écrite. –

2

Ce que tout le monde dit d'autre, plus:

Lorsque vous avez plusieurs éléments que vous voulez exclure, utilisez un set au lieu d'une chaîne de and s ou tuple:

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

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

Justification: Recherche tuple prend un temps proportionnel à la position de l'élément trouvé; l'échec prend le même temps que le dernier élément. Rechercher un élément dans un ensemble prend le même temps pour tous les éléments, et pour l'échec. Les ensembles gagnent généralement pour un grand nombre d'objets. Tout dépend de la probabilité que chaque élément soit recherché et de la probabilité d'échec. Les tuples peuvent gagner même avec une grande collection quand il y a une forte probabilité de quelques objets (ils devraient être placés à l'avant de l'uplet) et un faible risque d'échec.

+0

merci, tout avantage d'utiliser Sets vs tuples? –

+1

@ V3ss0n: voir ma réponse éditée. –

+0

Merci beaucoup. J'ai utilisé des listes lors de la comparaison dans la compréhension de la liste. Je devrais changer pour les ensembles. Ces listes sont grandes, ce sont des listes de fichiers qui ont 20k + éléments. –

1

Vous pouvez également utiliser une liste de compréhension à la place du filtre.

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

ou une expression du générateur (en fonction de vos besoins)

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

Oui, je viens d'utiliser des listes de compréhension. Mais le filtre de pensée est plus lisible, et j'ai fatigué les filtres, c'est la première fois que j'utilise le filtre. , je n'utilise généralement pas de filtres ou de cartes, juste la liste des compréhensions –

+1

@ V3ss0n C'est pourquoi vous devriez vous en tenir aux compréhensions - précisément parce qu'elles sont plus faciles à lire et à comprendre! – fmark

4

my logic is correct

En fait, non, ce n'est pas, comme l'a souligné dans d'autres réponses.

loin plus propre moyen d'atteindre le résultat souhaité est d'utiliser list comprehensions, savoir:

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

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

Cela dit, il n'y a pas de temps comme le présent pour brosser sur votre Boolean logic!

Si vous deviez tester votre code à l'unité, vous découvrirez rapidement que votre deuxième fonction de filtrage ne répond pas à vos attentes. Voici un exemple simpliste:

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