4

我遇到了一些看起来像的代码:

[func(val) for val in iterable]

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

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

如果返回值func总是计算为False,那么以下工作:

any(func(val) for val in iterable)

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

all(func(val) for val in iterable)

如果 func 的返回值可以计算为TrueFalse

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

我想出的最好的是:

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

或者

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

3 回答 3

4

大概只是

for val in iterable:
   func(val)

是最清楚的。

for val in iterable: func(val)

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

于 2020-06-16T12:07:37.210 回答
1

使用setwithbool函数怎么样?

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

已编辑:
看了@gelonida 的分析后,我相信以下内容会更快一些。

{None for val in iterable(N) if func(val)}
于 2020-06-16T13:33:36.573 回答
1

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

@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

于 2020-06-17T00:12:24.230 回答