понимание списка прорывов - PullRequest
47 голосов
/ 05 марта 2012

Как я могу нарушить понимание списка на основе условия, например, когда найдено число 412?

Код:

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]

Так что функционально, это было бы то, что вы можете сделать вывод, что это должно сделать:

even = [n for n in numbers if 0 == n % 2 and break if n == 412]

Я действительно предпочитаю:

  • однострочник
  • нет других модных библиотек, таких как itertools, если возможно, «чистый python» (читай: решение не должно использовать оператор import или аналогичный)

Ответы [ 7 ]

51 голосов
/ 05 марта 2012

Используйте функцию, чтобы поднять StopIteration и list, чтобы поймать ее:

>>> 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]

Для тех, кто жалуется, это не однострочник:

even = list(next(iter(())) if n == 412 else n for n in numbers if 0 == n % 2)

Для тех, кто жалуется, он хакерский и не должен использоваться в рабочем коде: ну, вы правы. Определенно.

42 голосов
/ 05 марта 2012

Вы можете использовать выражения генератора вместе с itertools.takewhile():

even_numbers = (n for n in numbers if not n % 2)
list(itertools.takewhile(lambda x: x != 412, even_numbers))

Редактировать : Я только что заметил требование не использовать никакие import с. Ну, я все равно оставляю здесь этот ответ.

13 голосов
/ 05 марта 2012

Если 412 обязательно будет в списке, вы можете использовать это:

even = [n for n in numbers[:numbers.index(412)] if not n % 2]

Если вы хотите включить 412 в результат, просто используйте numbers[:numbers.index(412)+1] для среза.

Примечаниечто из-за среза это будет менее эффективно (по крайней мере, с точки зрения памяти), чем itertools или для решения цикла.

12 голосов
/ 06 октября 2017

Я знаю, что это ОЧЕНЬ СТАРЫЙ пост, однако, поскольку ОП спросил об использовании break внутри list-comprehension, и я также искал что-то подобное, я подумал, что опубликую свои выводы здесь для дальнейшего использования.

При исследовании break я натолкнулся на малоизвестную особенность iter как iter(callable, sentinel), которая возвращает итератор, который "ломает" итерацию после вызова function значение равно sentinelзначение.

>>> 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.

Сложная задача - определить функцию, которая бы подходила для данной задачи.В этом случае сначала нам нужно преобразовать данные list из numbers в iterator, используя x = iter(numbers), который подает в качестве внешней переменной функцию lambda.

Затем наша вызываемая функция - это простовызовите итератор, чтобы выплюнуть следующее значение.Затем итератор сравнивает с нашим значением дозорного (в данном случае 412) и «ломается», как только это значение будет достигнуто.

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]
12 голосов
/ 28 ноября 2012
even = [n for n in numbers[:None if 412 not in numbers else numbers.index(412)] if not n % 2] 

Просто взял код Ф.Дж. выше и добавил троичный, чтобы проверить, есть ли 412 в списке. По-прежнему «один вкладыш» и будет работать, даже если 412 отсутствует в списке.

4 голосов
/ 05 марта 2012

Синтаксис для отображения списка (включая списки) здесь: http://docs.python.org/reference/expressions.html#list-displays

Как видите, специального синтаксиса while или until нет. Ближайшее, что вы можете получить:

even_numbers = (n for n in numbers if 0 == n % 2)
list(itertools.takewhile(lambda x: x != 412, even_numbers))

(Код взят из ответа Свена Марнача, выложенного в то время, когда я печатал это).

0 голосов
/ 14 апреля 2019

другое хитрое однострочное решение для решения breaking in list comprehension с помощью условия end.

без использования numbers.index(412), может быть, немного быстрее?

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]

Примечание: это плохая идея. просто для удовольствия:)

как сказал @WolframH:

Для тех, кто жалуется, он хакерский и не должен использоваться в рабочем коде: ну, вы правы. Обязательно.

...