Comment puis-je briser une compréhension de liste basée sur une condition, par exemple lorsque le nombre 412
est trouvé?
Code:
numbers = [951, 402, 984, 651, 360, 69, 408, 319, 601, 485, 980, 507, 725, 547, 544,
615, 83, 165, 141, 501, 263, 617, 865, 575, 219, 390, 984, 592, 236, 105, 942, 941,
386, 462, 47, 418, 907, 344, 236, 375, 823, 566, 597, 978, 328, 615, 953, 345, 399,
162, 758, 219, 918, 237, 412, 566, 826, 248, 866, 950, 626, 949, 687, 217, 815, 67,
104, 58, 512, 24, 892, 894, 767, 553, 81, 379, 843, 831, 445, 742, 717, 958, 609, 842,
451, 688, 753, 854, 685, 93, 857, 440, 380, 126, 721, 328, 753, 470, 743, 527]
even = [n for n in numbers if 0 == n % 2]
Donc, fonctionnellement, ce serait quelque chose que vous pouvez déduire que cela est censé faire:
even = [n for n in numbers if 0 == n % 2 and break if n == 412]
Je vraiment préfère:
import
ou similaire)even = [n for n in numbers[:None if 412 not in numbers else numbers.index(412)] if not n % 2]
Je viens de prendre le code de F.J. ci-dessus et d'ajouter un ternaire pour vérifier si 412 est dans la liste. Toujours un "liner" et fonctionnera même si le 412 n'est pas dans la liste.
Utilisez une fonction pour augmenter StopIteration
et list
pour l'attraper:
>>> def end_of_loop():
... raise StopIteration
...
>>> even = list(end_of_loop() if n == 412 else n for n in numbers if 0 == n % 2)
>>> print(even)
[402, 984, 360, 408, 980, 544, 390, 984, 592, 236, 942, 386, 462, 418, 344, 236, 566, 978, 328, 162, 758, 918]
Pour ceux qui se plaignent, ce n'est pas un vol simple:
even = list(next(iter(())) if n == 412 else n for n in numbers if 0 == n % 2)
Pour ceux qui se plaignent, c'est hackish et ne devrait pas être utilisé dans le code de production: Eh bien, vous avez raison. Certainement.
Vous pouvez utiliser des expressions de générateur avec itertools.takewhile()
:
even_numbers = (n for n in numbers if not n % 2)
list(itertools.takewhile(lambda x: x != 412, even_numbers))
Edit: Je viens de remarquer l'exigence de ne pas utiliser de import
s. Eh bien, je laisse cette réponse ici de toute façon.
Si 412 sera définitivement dans la liste, vous pouvez utiliser ceci:
even = [n for n in numbers[:numbers.index(412)] if not n % 2]
Si vous souhaitez inclure 412 dans le résultat, utilisez simplement numbers[:numbers.index(412)+1]
pour la tranche.
Notez qu'en raison de la tranche, cela sera moins efficace (au moins en termes de mémoire) qu'un itertools ou une solution de boucle.
Je sais que c'est un très vieux message, mais depuis qu'OP m'a demandé d'utiliser break
dans un list-comprehension
Et que je cherchais également quelque chose de similaire, j'ai pensé publier mes résultats ici pour référence future.
En enquêtant sur break
, je suis tombé sur une fonction peu connue de iter
sous la forme iter(callable, sentinel)
qui renvoie un itérateur qui "casse" itération une fois appelable function
value est égal à sentinel
value.
>>> help(iter)
Help on built-in function iter in module __builtin__:
iter(...)
iter(collection) -> iterator
iter(callable, sentinel) -> iterator
Get an iterator from an object. In the first form, the argument must
supply its own iterator, or be a sequence.
In the second form, the callable is called until it returns the sentinel.
La partie délicate ici consiste à définir une fonction qui conviendrait à un problème donné. Dans ce cas, nous devons d'abord convertir un list
de numbers
en iterator
en utilisant x = iter(numbers)
qui se nourrit en tant que variable externe en lambda
une fonction.
Ensuite, notre fonction appelable est juste un appel à l'itérateur pour cracher la valeur suivante. L'itérateur compare ensuite avec notre valeur sentinelle (412 dans ce cas) et "casse" une fois cette valeur atteinte.
print [i for i in iter(lambda x=iter(numbers): next(x),412) if i %2 == 0]
>>>
[402, 984, 360, 408, 980, 544, 390, 984, 592, 236, 942, 386, 462, 418,
344, 236, 566, 978, 328, 162, 758, 918]
La syntaxe pour les affichages de liste (y compris les compréhensions de liste) est ici: http://docs.python.org/reference/expressions.html#list-displays
Comme vous pouvez le voir, il n'y a pas de syntaxe spéciale while
ou until
. Le plus proche que vous pouvez obtenir est:
even_numbers = (n for n in numbers if 0 == n % 2)
list(itertools.takewhile(lambda x: x != 412, even_numbers))
(Code extrait de la réponse de Sven Marnach, affiché pendant que je tapais ceci).
une autre solution en ligne sournoise pour résoudre breaking in list comprehension
, à l'aide de la condition end
.
sans utiliser numbers.index(412)
, peut-être un peu plus vite?
even = [n for end in [[]] for n in numbers
if (False if end or n != 412 else end.append(42))
or not end and not n % 2]
Remarque: c'est une mauvaise idée. juste pour le fun : )
comme l'a dit @WolframH:
Pour ceux qui se plaignent, c'est hackish et ne devrait pas être utilisé dans le code de production: Eh bien, vous avez raison. Certainement.