6

J'ai une situation avec des listes parallèles qui doivent être filtrées en fonction des valeurs de l'une des listes. Parfois, j'écris quelque chose comme ça pour les filtrer:Traitement d'un cas vide avec filtrage et déballage de tuple

lista = [1, 2, 3] 
listb = [7, 8, 9] 
filtered_a, filtered_b = zip(*[(a, b) for (a, b) in zip(lista, listb) if a < 3]) 

Cela donne filtered_a == (1, 2) et filtered_b == (7, 8)

Cependant, en changeant la condition finale de a < 3 à a < 0 provoque une exception à soulever:

Traceback (most recent call last): 
    ... 
ValueError: need more than 0 values to unpack 

Je sais pourquoi cela se passe: la compréhension de la liste est vide, donc c'est comme appeler zip(*[]), ce qui est comme zip(), qui vient de revenir ns une liste vide qui ne peut pas être décompactée en iterables séparés filter_a et filtered_b.

Y a-t-il une meilleure fonction de filtrage (plus courte, plus simple, plus pythonique) qui gère le cas vide? Dans le cas vide, je m'attendrais à ce que filter_a et filtered_b soient des iterables vides afin que tout code suivant puisse rester inchangé.

+1

Qu'est-ce que vous attendez de ce que 'filtered_a' et' filtered_b' soient dans ce cas? «Aucun»? Tuples/listes vides? –

+0

@TomDalton - Oublié ça, merci. Ajouté à la question maintenant: "Dans le cas vide, je m'attendrais à filter_a, et filter_b à être iterables vides afin que tout code suivant puisse rester inchangé." – Justin

Répondre

4

Vous pouvez simplement court-circuit avec les valeurs par défaut:

filtered_a, filtered_b = zip(*[(a, b) for a, b in zip(lista, listb) if a < 0]) or ([], []) 
print(filtered_b, filtered_a) 
# [] [] 

Pour Python 3, vous aurez besoin d'appeler list sur l'itérateur retourné par zip donc le premier opérande peut être évalué comme une liste vide (pas un itérateur), sinon la valeur par défaut n'est jamais atteinte même si l'itérateur est potentiellement vide depuis bool(iter([])) est True.

1

je ferais probablement quelque chose comme:

lista = [1, 2, 3] 
listb = [7, 8, 9] 

filtered_abs = ((a, b) for (a, b) in zip(lista, listb) if a < 3]) 

for a, b in filtered_abs: 
    do_thing(a, b)