1

假设我有一个执行一些繁重计算的函数。

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()了两次。

4

5 回答 5

7

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

next(y for y in (f(x) for x in my_list) if y != 0)
于 2015-08-30T00:44:05.987 回答
4

正如Blckknght已经提到的,有一种使用生成器表达式的方法,但是您的问题中的函数也没有任何问题。并非所有内容都必须是单行的:)。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则会引发异常。您可以将其更改为您想要的任何内容。

于 2015-08-30T00:53:57.870 回答
1

也许使用itertools.ifilter

from itertools import ifilter
next(ifilter(lambda x: f(x) != 0, my_list))
于 2015-08-30T00:45:45.943 回答
1

理解可能是带有选项过滤输入的嵌套映射函数。在这种情况下,您想要过滤输出,所以这样做。让 y = f(x) = x x 并让 c(y) = (y > 100)。然后 (y for y in (x x for x in my_list) if 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
于 2015-08-30T01:16:17.430 回答
0

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

def f(x):
    for i in x:
        yield i

是的,这是一个空委托,但是您的示例可以用于您的功能(我不明白的意图所以没有猜到)。

于 2015-08-30T00:43:27.643 回答