Compréhension de liste sur une ligne: variantes if-else


178

Il s'agit davantage de la syntaxe de compréhension de liste python. J'ai une compréhension de liste qui produit une liste de nombres impairs d'une plage donnée:

[x for x in range(1, 10) if x % 2]

Cela fait un filtre - j'ai une liste source, où je supprime les nombres pairs ( if x % 2). J'aimerais utiliser quelque chose comme si-alors-autre ici. Le code suivant échoue:

>>> [x for x in range(1, 10) if x % 2 else x * 100]
  File "<stdin>", line 1
    [x for x in range(1, 10) if x % 2 else x * 100]
                                         ^
SyntaxError: invalid syntax

Il existe une expression python comme if-else:

1 if 0 is 0 else 3

Comment l'utiliser dans une compréhension de liste?


1
Fow ce que ça vaut, vous avez une "compréhension de liste", pas un générateur. La syntaxe ultime est la même sauf que les générateurs utilisent à la ()place de [].
mgilson


2
Il m'a fallu un certain temps pour comprendre pourquoi if x % 2 élimine les nombres pairs (au lieu de les garder) - c'est parce que quand xmême l' x % 2expression aboutit 0, qui, à son tour, évalue à False, tandis que tout intsauf 0évalue à True.

Réponses:


328

x if y else zest la syntaxe de l'expression que vous renvoyez pour chaque élément. Il vous faut donc:

[ x if x%2 else x*100 for x in range(1, 10) ]

La confusion vient du fait que vous utilisez un filtre dans le premier exemple, mais pas dans le second. Dans le deuxième exemple, vous ne mappez chaque valeur que sur une autre, en utilisant une expression d'opérateur ternaire.

Avec un filtre, vous avez besoin de:

[ EXP for x in seq if COND ]

Sans filtre, vous avez besoin de:

[ EXP for x in seq ]

et dans votre deuxième exemple, l'expression est "complexe", qui se trouve à impliquer un if-else.


2
J'ai une question ... [x for x in range(1, 10) if x % 2]est la syntaxe correcte. [x if x % 2 for x in range(1, 10)]- ce n'est pas, mais [x if x%2 else x*100 for x in range(1, 10)]c'est encore une syntaxe correcte. Comment venir?
ducin

@tkoomzaaskz dans votre deuxième exemple, ce n'est ni un opérateur ternaire-if-else (il manque le else), ni un filtre (puisqu'il s'agit de la EXPpartie de la compréhension de la liste)
shx2

3
@tkoomzaaskz Pour clarifier davantage, notez que vous pouvez en ajouter un second ifà la fin: [x if x%2 else x*100 for x in range(1, 10) if not x%3]le premier iffait partie de l'opérateur ternaire, le second iffait partie de la syntaxe de compréhension de liste. Le tout x if x%2 else x*100est "au même niveau" qu'un simple 2*x, c'est l'expression à évaluer sur le côté gauche du for, lorsque le filtrage de if not x%3a déjà eu lieu.
zx81

Bonjour, une instruction sur une ligne serait-elle plus performante que de la faire sur deux lignes comme for i in x:puis dans la boucle for if i == y:?
Alexis.Rolland

23
[x if x % 2 else x * 100 for x in range(1, 10) ]

12

Vous pouvez également faire cela avec la compréhension de liste:

A=[[x*100, x][x % 2 != 0] for x in range(1,11)]
print A

1
Très agréable. Une tranche booléenne. Merci, vous venez de me donner une solution plus facile à lire.

Vous pouvez également doubler l'attribution comme suit: A, B = [10,11] [a == 19], [1,14] [a == 20]
Stefan Gruenwald

10

Juste une autre solution, j'espère que quelqu'un pourra l'aimer:

Utilisation de: [False, True] [Expression]

>>> map(lambda x: [x*100, x][x % 2 != 0], range(1,10))
[1, 200, 3, 400, 5, 600, 7, 800, 9]
>>>

3

J'ai pu faire ça

>>> [x if x % 2 != 0 else x * 100 for x in range(1,10)]
    [1, 200, 3, 400, 5, 600, 7, 800, 9]
>>>
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.