Using break in a list comprehension
Solution 1:
Use a function to raise StopIteration
and list
to catch it:
>>> 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]
For those complaining it is not a one-liner:
even = list(next(iter(())) if n == 412 else n for n in numbers if 0 == n % 2)
For those complaining it is hackish and should not be used in production code: Well, you're right. Definitely.
Solution 2:
You can use generator expressions together with itertools.takewhile()
:
even_numbers = (n for n in numbers if not n % 2)
list(itertools.takewhile(lambda x: x != 412, even_numbers))
Edit: I just noticed the requirement not to use any import
s. Well, I leave this answer here anyway.
Solution 3:
even = [n for n in numbers[:None if 412 not in numbers else numbers.index(412)] if not n % 2]
Just took F.J.'s code above and added a ternary to check if 412 is in the list. Still a 'one liner' and will work even if 412 is not in the list.
Solution 4:
I know this is a VERY OLD post, however since OP asked about using break
inside a list-comprehension
and I was also looking for something similar, I thought I would post my findings here for future reference.
While investigating break
, I came across little known feature of iter
as iter(callable, sentinel)
which return an iterator that "breaks" iteration once callable function
value is equal to 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.
Tricky part here is defining a function that would fit given problem. In this case first we need to convert given list
of numbers
to an iterator
using x = iter(numbers)
which feeds as external variable into lambda
function.
Next, our callable function is just a call to the iterator to spit out next value. The iterator then compares with our sentinel value (412 in this case) and "breaks" once that value is reached.
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]
Solution 5:
If 412 will definitely be in the list you could use this:
even = [n for n in numbers[:numbers.index(412)] if not n % 2]
If you want to include 412 in the result just use numbers[:numbers.index(412)+1]
for the slice.
Note that because of the slice this will be less efficient (at least memory-wise) than an itertools or for loop solution.