2010-10-15 30 views
4

(avec Python 3.1)filtre Python/combo max - pour vérifier iterator vide

Je sais que cette question a été posée à plusieurs reprises la question générale des tests si iterator est vide; évidemment, il n'y a pas de bonne solution à cela (je suppose pour une raison - un itérateur ne sait pas vraiment s'il est vide jusqu'à ce qu'on lui demande de retourner sa prochaine valeur).

J'ai un exemple précis, cependant, et espérait que je peux faire un code propre et Pythonic sortir:

#lst is an arbitrary iterable 
#f must return the smallest non-zero element, or return None if empty 
def f(lst): 
    flt = filter(lambda x : x is not None and x != 0, lst) 
    if # somehow check that flt is empty 
    return None 
    return min(flt) 

Y at-il une meilleure façon de le faire?

EDIT: désolé pour la notation stupide. Le paramètre de la fonction est en effet un itérable arbitraire, plutôt qu'une liste.

+0

Utilisez-vous Python 3? –

+0

Oui. ActiveState Python 3.1.2. – max

+1

'itertools.c_c_c_c_c_COMBO_BREAKER()' –

Répondre

4
def f(lst): 
    flt = filter(lambda x : x is not None and x != 0, lst) 
    try: 
    return min(flt) 
    except ValueError: 
    return None 

min lancers ValueError lorsque la séquence est vide. Cela suit le paradigme commun «Plus facile de demander pardon».

EDIT: Une solution à base de réduire sans exceptions

from functools import reduce 
def f(lst): 
    flt = filter(lambda x : x is not None and x != 0, lst) 
    m = next(flt, None) 
    if m is None: 
    return None 
    return reduce(min, flt, m) 
+0

J'ai peur que 'ValueError' soit déclenché par autre chose qu'une liste vide. Est-il connu avec une certitude de 100% que min n'augmentera pas ValueError dans toute autre circonstance? En outre, il se peut que je doive remplacer 'lst' par une liste de compréhension; et dans ce cas, j'ai encore plus peur de 'ValueError' causé par mon propre code dans la compréhension de la liste. – max

+0

@max, je ne suis pas positif, puisque Python n'est pas génial pour documenter ce genre de chose. Cependant, 'flt' devrait toujours être itérable. Et même si ça ne l'était pas, on dirait que 'min' lance' TypeError' si vous passez un argument du mauvais type. Je ne peux pas penser à quoi que ce soit que «min» lui-même lancerait. Maintenant, il semble que 'lst' est actuellement une liste. Certes, c'est un nom trompeur sinon. Dans ce cas, vous n'avez pas à vous soucier de la compréhension de la liste, car elle est complètement terminée avant le démarrage de 'f'. Si c'est une compréhension génératrice, c'est un peu plus compliqué. –

+0

On dirait que c'est un peu dangereux si Python ne documente pas ce genre de chose. Je suis, après tout, en train d'écrire le logiciel pour le module de support de vie sur le vaisseau spatial qui amène les colons humains à ... Ah, ça ne fait rien :) mais je préfère ne pas me fier à un type d'exception spécifique. – max

1
def f(lst): 
    # if you want the exact same filtering as the original, you could use 
    # lst = [item for item in lst if (item is not None and item != 0)] 

    lst = [item for item in lst if item] 
    if lst: return min(lst) 
    else: return None 

la compréhension de la liste ne permet que des éléments qui n'évaluent pas Boolean false (qui filtre 0 et None)

une liste vide ie [] va évaluer à False, donc "if lst:" ne se déclenchera que si la liste contient des éléments

+1

oui, mais il filtre aussi par ex. '' "' ',' [] ',' set() ',' tuple() '... – katrielalex

+0

il est assez simple de remplacer" if item "par un ensemble plus strict si vous voulez, mais je ne pense pas" ", [], set(), tuple() compte comme non nul de toute façon;) On dirait qu'il va passer NUMBERS avec son appel min(). – lunixbochs

0

vous pouvez aussi réduire l'expression return reduce(lambda a,b: a<b and a or b,x) or None

+0

Cela ne répond pas à la question de l'OP, cela pose toujours des problèmes avec les itérateurs vides ou les listes vides. – leetNightshade