通过平均减少列表的优雅方式?

gok*_*gok 5 python list

有没有更优雅的方式来编写这个功能?

def reduce(li):
    result=[0 for i in xrange((len(li)/2)+(len(li)%2))]
    for i,e in enumerate(li):
        result[int(i/2)] += e
    for i in range(len(result)):
        result[i] /= 2
    if (len(li)%2 == 1):
        result[len(result)-1] *= 2
    return result
Run Code Online (Sandbox Code Playgroud)

在这里,它做了什么:

a = [0,2,10,12]
b = [0,2,10,12,20]
reduce(a)
>>> [1,11]
reduce(b)
>>> [1,11,20]
Run Code Online (Sandbox Code Playgroud)

它取偶数和奇数索引的平均值,如果列表具有奇数个元素,则保留最后一个索引

And*_*nca 8

你真正想做的是通过你的列表应用2个样本的移动平均值,数学上你会卷积[.5,.5]的窗口,然后只取偶数样本.为了避免将奇数数组的最后一个元素除以2,您应该复制它,这不会影响偶数数组.

使用numpy它变得非常优雅:

import numpy as np

np.convolve(a + [a[-1]], [.5,.5], mode='valid')[::2]
array([  1.,  11.])

np.convolve(b + [b[-1]], [.5,.5], mode='valid')[::2]
array([  1.,  11.,  20.])
Run Code Online (Sandbox Code Playgroud)

你可以使用list(outputarray)转换回列表.

如果性能很重要,使用numpy是非常有用的,优化的C数学代码正在做的工作:

In [10]: %time a=reduce(list(np.arange(1000000))) #chosen answer
CPU times: user 6.38 s, sys: 0.08 s, total: 6.46 s
Wall time: 6.39 s

In [11]: %time c=np.convolve(list(np.arange(1000000)), [.5,.5], mode='valid')[::2]
CPU times: user 0.59 s, sys: 0.01 s, total: 0.60 s
Wall time: 0.61 s
Run Code Online (Sandbox Code Playgroud)