一个班轮通过一个可迭代的(生成器)

one liner to go through an iterable (generator)

我遇到了一些代码,如下所示:

[func(val) for val in iterable]

有一个可迭代对象(在我的例子中是一个生成器),用户希望为其每个值调用一个函数来解决它的副作用(例如,func 可能只是 print)但是其中 return 值无关紧要。

我不喜欢这种方法的一点是,创建了一个临时的 list,如果生成器产生大量值,这可能会消耗相当多的内存。

如果 func 的 return 值始终计算为 False,则以下工作:

any(func(val) for val in iterable)

如果 func 的 return 值始终计算为 True,则以下工作:

all(func(val) for val in iterable)

如果 func 的 return 值可以计算为 TrueFalse

,我该怎么办

还有什么比将值强制为 False 更好的吗?

我想到的最好的是:

any(func(val) and False for val in iterable)

all(func(val) or True for val in iterable)

可能只是

for val in iterable:
   func(val)

最清楚。

for val in iterable: func(val)

如果确实需要单线,则可用。

使用带有 bool 函数的 set 怎么样?

{bool(func(val)) for val in iterable}

已编辑:
看了@gelonida的分析,相信下面的速度会快一些。

{None for val in iterable(N) if func(val)}

只是给定答案/潜在解决方案的综合和时序分析

@LeopardShark 的答案似乎是最短、最易读的答案。 并且名列前茅。 (时间不准确,我没有看字节码)

速度明智 - @LeopardShark 的回答 - @ywbaek 的第二个建议 - 初始代码,如果 N 不是太大 (~10000) - 我在问题中发布的建议

初始代码存在白白分配释放内存的缺点

我在问题中建议的代码的缺点是理解起来不太直观,如果弄乱了 (all, any) 和 (and False, or True) 可能无法按预期执行所有操作,而且性能也稍差

@ywbaek 的解决方案比我的建议更安全,也更直观,但执行速度更快。

最简单的解决方案有一个小缺点,即不能用作 lambda。

我的时间代码:

N=10000
M=500

called = 0
def func(v):
    global called
    called += 1
    v * v * v * v * v *v / (v+0.1)

def iterable(N):
    for v in range(N):
        v * 2
        yield v

def testrun():
    global called
    called=0
    print(timeit(test, number=M), end=" ")
    print(called)

print("consume some CPU")
timeit(lambda: 3**.5 **.2) # it seems, that timeit is a little more predictable if I let the process warm up a little

print("Start measures")

def test():
    for val in iterable(N): func(val)
testrun()

def test():
    {None for val in iterable(N) if func(val)}
testrun()

def test():
    [func(val) for val in iterable(N)]
testrun()

def test():
    all(func(val) or True for val in iterable(N))
testrun()

def test():
    any(func(val) and False for val in iterable(N))
testrun()

我的旧电脑上的结果:

consume some CPU
Start measures
3.864932143012993 5000000
3.916696268017404 5000000
4.0817033689818345 5000000
4.293206526956055 5000000
4.319622751965653 5000000