生成器表达式包括条件测试而不调用函数两次?

时间:2015-08-30 00:34:53

标签: python python-3.x generator-expression

假设我有一个执行大量计算的函数。

def f(x):
    ... 
    return result

然后我有一个列表,其中包含我想要传递给f()的值:

my_list = [2, 98, 4, 34, 23, 11]

我想在此列表中找到第一个元素x,用于验证f(x)上的条件(让我们说例如f(x) != 0),并获得此计算结果

基本上,我会像这样写一个for循环:

def first_match(my_list):
    for x in my_list:
        r = f(x)
        if r != 0:
            return r

我想知道是否有办法使用生成器表达式获得相同的结果?

到目前为止我的想法是这样的:

r = next(f(x) if f(x) != 0 for x in my_list)

问题是这会两次调用f()

5 个答案:

答案 0 :(得分:5)

您可以使用嵌套的生成器表达式来避免双重函数调用:

Application

答案 1 :(得分:4)

有一种方法可以使用生成器表达式,already mentionedBlckknght,但问题中的first_match()函数也没有错。并非所有事情都必须是单行代码:)。

以下是另一种方法:

try:
    from itertools import ifilter as filter  # Python 2
except ImportError:
    pass  # Python 3

predicate = lambda x: x != 0
r = next(filter(predicate, (f(x) for x in my_list)), None)

next()(上面代码中的None)的第二个参数是,如果迭代器中没有任何内容作为第一个参数传入,则返回什么。如果您没有指定它并且迭代器已用尽,则会引发StopIteration异常。您可以将其更改为您想要的任何内容。

答案 2 :(得分:1)

也许使用itertools.ifilter

from itertools import ifilter
next(ifilter(lambda x: f(x) != 0, my_list))

答案 3 :(得分:1)

理解可能是嵌套的地图功能,可选择过滤输入。在这种情况下,您希望过滤输出,因此请执行此操作。令y = f(x)= x x并且令c(y)=(y> 100)。然后(y为y in(x x代表my_list中的x),如果y> 100)给出滤波后的输出。正如您所注意到的那样,可以使用next来完成对第一个真元素(第一个真实搜索)的过滤器停止。

my_list = [2, 98, 4, 34, 23, 11]
ge = (y for y in (x*x for x in my_list) if y > 100)

print(next(ge))
# 9604

答案 4 :(得分:0)

通常,生成器表达式可以构造为生成器函数。例如,这个f(x)具有延迟评估,正如您对生成器所期望的那样:

perl -e 'exit(65280)'
echo $?   # returns 0

是的,这是一个空委托,但你的例子可以用于你的功能(我不明白这样做的意图没有猜测)。