如何将此生成器函数转换为lambda表达式

时间:2018-07-13 04:12:18

标签: python lambda generator list-comprehension

def f(nums):
    sum = 0
    for i in nums:
        sum += i
        yield sum

根据args nums(类型列表),我试图使用列表推导来创建一个新列表,该列表的每个索引值都是以前的累加值。

最终结果看起来像[i for i in f(nums)]

是否可以将函数转换为lambda表达式?或其他任何使它成为一行的东西?

3 个答案:

答案 0 :(得分:4)

这是一种实现方法:

nums=[1,2,3,4]

[sum(nums[:idx+1]) for idx, i in enumerate(nums)]

输出:

[1, 3, 6, 10]

另一种方法是使用@Blckknght建议的itertools.accumulate

from itertools import accumulate

list(accumulate(nums))

输出:

[1, 3, 6, 10]

答案 1 :(得分:1)

我将建议以下内容代替

nums=[1,2,3,4]
gen=(sum(li[0:i]) for i,_ in enumerate(li,1))

这是一个生成器,因此尚未对不需要的元素执行O(n^2)操作。

然后使用next来获取元素:

>>> next(gen)
1
>>> next(gen)
3
>>> next(gen)
6
>>> next(gen)
10

如果您一次想要它们,只需在生成器上使用list

>>> gen=(reduce(add, li[0:i]) for i,_ in enumerate(li,1))
>>> list(gen)
[1, 3, 6, 10]]

此功能在非平凡列表上的性能很差,因为它的复杂度为O(n^2)。只是出于好奇。请参见下面的时间。


(感谢AChampion)另一个减少:

>>> reduce(lambda x, y: x+[y+next(iter(x[-1:]), 0)], nums, [])
[1, 3, 6, 10]

但是正确的答案是itertools.accumulate或您的原始功能。任何一行解决方案都将具有更大的计算复杂性。


以下是一组时序,表明除itertools.accumulate之外,单行替换还具有O(n^2)类型的复杂性(即,多10倍的项目,大约100倍的时间)。这是因为对于列表中的每个元素,由于lambda或reduce或comprehensions没有任何形式的累加器,因此必须再次循环到该点为止的整个列表。您的原始函数和itertools.accumulate的类型复杂度均为O(n)(即,项目增加10倍,线性时间增加10倍)。

Here是O复杂度的图形和备忘单。

时间和结果如下:

from itertools import accumulate
from functools import reduce 

def f1(nums):
    sum_ = 0
    for i in nums:
        sum_ += i
        yield sum_

def f2(nums):
    return (sum(nums[0:i]) for i,_ in enumerate(nums,1))

def f3(nums):
    return  accumulate(nums)

def f4(nums):
    return reduce(lambda x, y: x+[y+next(iter(x[-1:]), 0)], nums, [])

if __name__=='__main__':
    import timeit    
    for case, x in (('small',100),('med',1000),('large',10000),('huge',100000)):  
        data=list(range(x))
        print("Case {}, {:,} x, All equal: {}".format(case,x,(list(f1(data))==list(f2(data))==list(f3(data))==list(f4(data)))))
        for f in (f1,f2,f3,f4):
            print("   {:^10s}{:.4f} secs".format(f.__name__, timeit.timeit("list(f(data))", setup="from __main__ import f, data", number=10)))

结果:

Case small, 100 x, All equal: True
       f1    0.0001 secs
       f2    0.0007 secs
       f3    0.0000 secs
       f4    0.0006 secs
Case med, 1,000 x, All equal: True
       f1    0.0007 secs
       f2    0.0424 secs
       f3    0.0003 secs
       f4    0.0139 secs
Case large, 10,000 x, All equal: True
       f1    0.0083 secs
       f2    3.9526 secs
       f3    0.0036 secs
       f4    1.2756 secs
Case huge, 100,000 x, All equal: True
       f1    0.0977 secs
       f2    427.4129 secs
       f3    0.0532 secs
       f4    159.2506 secs

答案 2 :(得分:0)

如果列表是连续的。

一种简单但不高效的方法:

[sum(range(1, i+1)) for i in range(1, 5))]

输出:

[1, 3, 6, 10]