si / sinon dans une liste de compréhension

Réponses:

1461

Vous pouvez totalement faire ça. C'est juste un problème de commande:

[unicode(x.strip()) if x is not None else '' for x in row]

En général,

[f(x) if condition else g(x) for x in sequence]

Et, pour les listes de compréhension avec ifconditions uniquement,

[f(x) for x in sequence if condition]

Notez que cela utilise en fait une construction de langage différente, une expression conditionnelle , qui elle-même ne fait pas partie de la syntaxe de compréhension , tandis que l' ifafter for…infait partie des compréhensions de liste et sert à filtrer les éléments de la source itérable.


Les expressions conditionnelles peuvent être utilisées dans toutes sortes de situations où vous souhaitez choisir entre deux valeurs d'expression en fonction d'une condition. Cela fait la même chose que l' opérateur ternaire ?:qui existe dans d'autres langues . Par exemple:

value = 123
print(value, 'is', 'even' if value % 2 == 0 else 'odd')
poussée
la source
141
Notez que la if / else ici est maintenant la syntaxe "opérateur ternaire" et non la syntaxe de compréhension de liste.
Adam Vandenberg
8
C'est pourquoi je préfère mettre l'opérateur ternaire entre crochets, il est plus clair que ce n'est qu'une expression normale, pas une compréhension.
Jochen Ritzel
17
Donc, l'astuce est "Dans la compression de liste, j'écris si avant pour alors je dois ajouter une autre partie aussi". parce que si mon l = [ 2, 3, 4, 5]alors [x if x % 2 == 0 for x in l]donne moi une erreur alors que ça [x if x % 2 == 0 else 200 for x in l]marche. Oui je sais que pour le filtrer je devrais l'écrire [ x for x in l if x % 2 == 0]. Désolé pour la peine. Merci pour votre réponse.
Grijesh Chauhan
5
Les documents python mentionnent l'opérateur ternaire . Notez qu'il nécessite le reste, ou cela ne fonctionne pas.
naught101
4
Les compréhensions @Drewdin List ne prennent pas en charge la rupture lors de son itération. Vous devrez alors utiliser une boucle normale.
poke
44

Une manière:

def change(f):
    if f is None:
        return unicode(f.strip())
    else:
        return ''

row = [change(x) for x in row]

Bien que vous ayez alors:

row = map(change, row)

Ou vous pouvez utiliser un lambda en ligne.

Adam Vandenberg
la source
13
C'est également une bonne (peut-être seulement) technique à utiliser lorsque vous devez gérer des exceptions possibles de l' ifexpression ou du code dans son ou le elsebloc d'instructions s. La réponse acceptée est meilleure pour les cas simples.
martineau
37

Voici un autre exemple illustratif:

>>> print(", ".join(["ha" if i else "Ha" for i in range(3)]) + "!")
Ha, ha, ha!

Il exploite le fait qu'il if iévalue Falsepour 0et Truepour toutes les autres valeurs générées par la fonction range(). Par conséquent, la compréhension de la liste s'évalue comme suit:

>>> ["ha" if i else "Ha" for i in range(3)]
['Ha', 'ha', 'ha']
Bengt
la source
37

Le problème spécifique a déjà été résolu dans les réponses précédentes, je vais donc aborder l'idée générale d'utiliser des conditions dans les listes de compréhension.

Voici un exemple qui montre comment les conditions peuvent être écrites dans une compréhension de liste:

X = [1.5, 2.3, 4.4, 5.4, 'n', 1.5, 5.1, 'a']     # Original list

# Extract non-strings from X to new list
X_non_str = [el for el in X if not isinstance(el, str)]  # When using only 'if', put 'for' in the beginning

# Change all strings in X to 'b', preserve everything else as is
X_str_changed = ['b' if isinstance(el, str) else el for el in X]  # When using 'if' and 'else', put 'for' in the end

Notez que dans la première liste de compréhension pour X_non_str, l'ordre est:

expression pour l' élément dans une condition itérable si

et dans la dernière liste de compréhension pour X_str_changed, l'ordre est:

expression1 si condition else expression2 pour l' élément dans l' itérable

J'ai toujours du mal à me rappeler que l' expression1 doit être antérieure à if et l' expression2 doit être postérieure à autre chose . Ma tête veut que les deux soient avant ou après.

Je suppose qu'il est conçu comme ça parce qu'il ressemble à un langage normal, par exemple "Je veux rester à l'intérieur s'il pleut, sinon je veux sortir"

En anglais simple, les deux types de compréhension de liste mentionnés ci-dessus pourraient être énoncés comme suit:

Avec seulement if:

extract_apple pour apple dans box_of_apples if apple_is_ripe

et avec if/else

mark_apple if apple_is_ripe else Leave_it_unmarked for apple in box_of_apples

Tim Skov Jacobsen
la source
7

Les autres solutions sont idéales pour un single if/ elseconstruct. Cependant, les déclarations ternaires dans les listes de compréhension sont sans doute difficiles à lire.

L'utilisation d'une fonction facilite la lisibilité, mais une telle solution est difficile à étendre ou à adapter dans un flux de travail où le mappage est une entrée. Un dictionnaire peut atténuer ces problèmes:

row = [None, 'This', 'is', 'a', 'filler', 'test', 'string', None]

d = {None: '', 'filler': 'manipulated'}

res = [d.get(x, x) for x in row]

print(res)

['', 'This', 'is', 'a', 'manipulated', 'test', 'string', '']
jpp
la source
1

Cela a à voir avec la façon dont la compréhension de la liste est effectuée.

Gardez à l'esprit les points suivants:

[ expression for item in list if conditional ]

Est équivalent à:

for item in list:
    if conditional:
        expression

Où le expressionest dans un format légèrement différent (pensez à changer l'ordre du sujet et du verbe dans une phrase).

Par conséquent, votre code [x+1 for x in l if x >= 45]fait ceci:

for x in l:
    if x >= 45:
        x+1

Cependant, ce code [x+1 if x >= 45 else x+5 for x in l]fait cela (après avoir réorganisé le expression):

for x in l:
    if x>=45: x+1
    else: x+5
arboc7
la source
0

Il n'y a aucun besoin de ternaire si / alors / sinon. À mon avis, votre question appelle cette réponse:

row = [unicode((x or '').strip()) for x in row]
mariotomo
la source
0

Faire une liste des éléments dans un itérable

Il semble préférable de généraliser d'abord toutes les formes possibles plutôt que de donner des réponses spécifiques aux questions. Sinon, le lecteur ne saura pas comment la réponse a été déterminée. Voici quelques formulaires généralisés que j'ai imaginés avant d'avoir mal à la tête en essayant de décider si une clause else finale pourrait être utilisée dans le dernier formulaire.

[expression1(item)                                        for item in iterable]

[expression1(item) if conditional1                        for item in iterable]

[expression1(item) if conditional1 else expression2(item) for item in iterable]

[expression1(item) if conditional1 else expression2(item) for item in iterable if conditional2]

La valeur de itemn'a pas besoin d'être utilisée dans aucune des clauses conditionnelles. A conditional3peut être utilisé comme commutateur pour ajouter ou non une valeur à la liste de sortie.

Par exemple, pour créer une nouvelle liste qui élimine les chaînes vides ou les chaînes d'espaces de la liste de chaînes d'origine:

newlist = [s for s in firstlist if s.strip()]
Hewey Dewey
la source
1
Le second donne une erreur comme Tim a répondu dans son commentaire, voir aussi les instructions conditionnelles dans les docs python. Qui me sont tout à fait illisibles. Résumé: seule this if condition else thatou une expression normale est autorisée. Non value = this if condition(ce qui peut être réalisé avec value = this if condition else None)
Anderium
0

Vous pouvez combiner la logique conditionnelle dans une compréhension:

 ps = PorterStemmer()
 stop_words_english = stopwords.words('english')
 best = sorted(word_scores.items(), key=lambda x: x[1], reverse=True)[:10000]
 bestwords = set([w for w, s in best])


 def best_word_feats(words):
   return dict([(word, True) for word in words if word in bestwords])

 # with stemmer
 def best_word_feats_stem(words):
   return dict([(ps.stem(word), True) for word in words if word in bestwords])

 # with stemmer and not stopwords
 def best_word_feats_stem_stop(words):
   return dict([(ps.stem(word), True) for word in words if word in bestwords and word not in stop_words_english])
Max Kleiner
la source
-2
# coding=utf-8

def my_function_get_list():
    my_list = [0, 1, 2, 3, 4, 5]

    # You may use map() to convert each item in the list to a string, 
    # and then join them to print my_list

    print("Affichage de my_list [{0}]".format(', '.join(map(str, my_list))))

    return my_list


my_result_list = [
   (
       number_in_my_list + 4,  # Condition is False : append number_in_my_list + 4 in my_result_list
       number_in_my_list * 2  # Condition is True : append number_in_my_list * 2 in my_result_list
   )

   [number_in_my_list % 2 == 0]  # [Condition] If the number in my list is even

   for number_in_my_list in my_function_get_list()  # For each number in my list
]

print("Affichage de my_result_list [{0}]".format(', '.join(map(str, my_result_list))))

(venv) $ python list_comp.py
Affichage de my_list [0, 1, 2, 3, 4, 5]
Affichage de my_result_list [0, 5, 4, 7, 8, 9]

Alors pour vous: row = [('', unicode(x.strip()))[x is not None] for x in row]

Trop Freshloïc
la source
Que signifie "Affichage de ..." ? C'est français?
Peter Mortensen