生成器表达式包括条件测试而不调用函数两次?
Generator expression including conditional test without calling a function twice?
假设我有一个执行一些繁重计算的函数。
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()
两次。
一般来说,生成器表达式可以构造成生成器函数。例如,这个 f(x) 具有惰性求值,正如您对生成器所期望的那样:
def f(x):
for i in x:
yield i
是的,这是一个空委托,但您的示例可以用于您的功能(我不明白其意图所以没有猜测)。
您可以使用嵌套的生成器表达式来避免双重函数调用:
next(y for y in (f(x) for x in my_list) if y != 0)
from itertools import ifilter
next(ifilter(lambda x: f(x) != 0, my_list))
有一种方法可以使用生成器表达式,如 by 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
)是 return 如果您作为第一个参数传入的迭代器中没有任何内容。如果您不指定它并且迭代器已用完,则会引发 StopIteration
异常。您可以将其更改为任何您想要的。
理解可能是嵌套的映射函数,带有输入的选项过滤。在这种情况下,您想要过滤输出,所以这样做。令 y = f(x) = xx 并令 c(y) = (y > 100)。然后 (y for y in (xx 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
假设我有一个执行一些繁重计算的函数。
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()
两次。
一般来说,生成器表达式可以构造成生成器函数。例如,这个 f(x) 具有惰性求值,正如您对生成器所期望的那样:
def f(x):
for i in x:
yield i
是的,这是一个空委托,但您的示例可以用于您的功能(我不明白其意图所以没有猜测)。
您可以使用嵌套的生成器表达式来避免双重函数调用:
next(y for y in (f(x) for x in my_list) if y != 0)
from itertools import ifilter
next(ifilter(lambda x: f(x) != 0, my_list))
有一种方法可以使用生成器表达式,如 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
)是 return 如果您作为第一个参数传入的迭代器中没有任何内容。如果您不指定它并且迭代器已用完,则会引发 StopIteration
异常。您可以将其更改为任何您想要的。
理解可能是嵌套的映射函数,带有输入的选项过滤。在这种情况下,您想要过滤输出,所以这样做。令 y = f(x) = xx 并令 c(y) = (y > 100)。然后 (y for y in (xx 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