1

I would like to generate a list by repeatedly calling a function till the function return a predefined value.

myList = [i,r = foo() while i==0]

myList = [r1, r2, r3, r4...] as long as returned i value is == 0

Is there a way to do this using list comprehension?

Pavan
  • 2,715
  • 4
  • 18
  • 19

4 Answers4

1
def stop_iteration():
    raise StopIteration

If foo() is a generator:

myList = list((i,r) if i != 0 else stop_iteration() for (i,r) in foo())

else:

def foo_generator():
    i,r = foo()
    while i != 0:
      yield i,r
      i,r = foo()

myList = list(foo_generator())
Benjamin Toueg
  • 10,511
  • 7
  • 48
  • 79
0

I don't think there is a one-liner for that. However, by defining a simple generator which would wrap any given foo-like function, you can do it.

TEST = [(0, 0), (1, 0), (2, 1), (3, 0)]


def foo():
    return TEST.pop(0)


def foo_wrapper(foo_like):
    r, i = foo_like()
    while i == 0:
        yield r
        r, i = foo_like()


print list(foo_wrapper(foo))
Eser Aygün
  • 7,794
  • 1
  • 20
  • 30
0

No, you cannot do that. The only keywords that list comprehensions support are for, if, and else (and lambda of course).

So, you have to do a multi-line solution. However there is no need to define a wrapper function. This will work fine:

mylist = []
while True:   
    i, r = foo()
    if i: break
    mylist.append(r)

In the end, mylist will have everything you want.

0

This is not recommended, but...

>>> def notyet(predicate):
        if predicate:
            raise StopIteration
        return True

>>> # note that below we're wrapping a generator expression in a 
>>> # call to `list` so that when `StopIteration` is raised your
>>> # program won't terminate.
>>> xs = list((i, r) for (i, r) in foo() if notyet(i!=0))
>>> # if we try this instead, your program will hit the buffers
>>> # when the predicate is satisfied.
>>> xs = [(i, r) for (i, r) in foo() if notyet(i!=0)]
Traceback (most recent call last):
  File "<pyshell#5>", line 1, in <module>
    xs = [(i, r) for (i, r) in foo() if notyet(i!=0)]
  File "<pyshell#3>", line 3, in notyet
raise StopIteration
StopIteration

It's much better to use itertools.takewhile in this situation.

>>> from itertools import takewhile
>>> xs = list(takewhile(lambda (i, r): i!=0, foo()))
superjump
  • 151
  • 4