在带有上限的python中累积

时间:2018-05-07 17:44:48

标签: python python-3.x

我有一个清单

nums=[1,2,4,6]

我想累积这个列表的上限为5,即如果累积值超过5的倍数,它应该打印5的倍数然后该值

预期产出:

1
3
5
7
10
13

编写的代码如下:

nums=[1,2,4,6]
from itertools import accumulate
a= accumulate(nums)

for i in a:
    print(i)

现在正在打印的输出

1
3
7
13

我如何获得所需的输出

2 个答案:

答案 0 :(得分:3)

这是使用生成器表达式的Pythonic方法:

In [12]: from itertools import accumulate, chain

In [13]: list(chain.from_iterable((i,) if i < 5
             else (next(j for j in range(i, 0, -1) if j%5 == 0), i)
                     for i in accumulate(nums)))
Out[13]: [1, 3, 5, 7, 10, 13]

逻辑是你循环累积的结果,然后对于大于5的数字,你会发现它之前的第一个数字(使用反向范围和next函数)是5的倍数。然后连接结果使用itertools.chain()

从算法的角度来看,不是在列表上执行多个循环,而是通过累积和另一个循环来查找预期的数字,您可以在一个遍历中执行此操作,如下所示:

In [18]: def myaccumulate(lst):
    ...:     total = 0
    ...:     for num in lst:
    ...:         total += num
    ...:         for i in range(total, num, -1):
    ...:             if i%5 == 0:
    ...:                 yield i
    ...:                 break
    ...:         yield total
    ...:    

演示:

In [19]: list(myaccumulate(nums))
Out[19]: [1, 3, 5, 7, 10, 13]

这种方法实际上比基于生成器的方法更快:

In [20]: %timeit list(myaccumulate(nums))
2.65 µs ± 47.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [21]: %timeit list(chain.from_iterable((i,) if i < 5 else (next(j for j in range(i, 0, -1) if j%5 == 0), i) for i in accumulate(nums)))
4.12 µs ± 21.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

答案 1 :(得分:1)

这是一种手动方式。效率不高,但可读。假设你正在处理正数。

from itertools import accumulate

nums = [1,2,4,6]

acc = list(accumulate(nums))  # regular accumulation
add = [i for i in range(5, acc[-1], 5) if i not in acc]  # multiples of 5 missing

res = sorted(acc + add)  # combine results and sort

print(res)

[1, 3, 5, 7, 10, 13]

使用set

可以采用另一种方法
add = list(set(range(5, acc[-1], 5)) - set(acc))