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?

ducine
la source
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.

shx2
la source
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) ]
lucasg
la source
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
Stefan Gruenwald
la source
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]
>>>
James Sapam
la source
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]
>>>
anudeep
la source