Python迭代数组,同时找到前k个元素的平均值

Stu*_*ent 19 python algorithm

假设我有一个Python数组a=[3, 5, 2, 7, 5, 3, 6, 8, 4].我的目标是一次遍历这个数组3个元素,返回三个元素中前2个的平均值.

使用上面的数组,在我的迭代步骤中,前三个元素是[3, 5, 2],前两个元素的平均值是4.接下来的三个元素是[5, 2, 7],前2个元素的平均值是6.接下来的三个元素是[2, 7, 5]和平均值前两个元素再次是6. ...

因此,上述数组的结果将是[4, 6, 6, 6, 5.5, 7, 7].

编写这样一个函数最好的方法是什么?

fos*_*ock 14

您可以使用列表的某些奇特切片来操作元素的子集.只需抓住每个三元素子列表,排序以找到前两个元素,然后找到简单平均值(aka.mean)并将其添加到结果列表中.

def get_means(input_list):
    means = []
    for i in xrange(len(input_list)-2):
        three_elements = input_list[i:i+3]
        sum_top_two = sum(three_elements) - min(three_elements)
        means.append(sum_top_two/2.0)
    return means
Run Code Online (Sandbox Code Playgroud)

你可以看到你的示例输入(和期望的结果),如下所示:

print(get_means([3, 5, 2, 7, 5, 3, 6, 8, 4]))
# [4.0, 6.0, 6.0, 6.0, 5.5, 7.0, 7.0]
Run Code Online (Sandbox Code Playgroud)

和更多...

还有其他一些很好的答案可以进入更多性能导向的答案,包括使用生成器避免大内存列表的答案:https://stackoverflow.com/a/49001728/416500

  • 您可以使用`sum_top_two = sum(three_elements) - min(three_elements)来避免排序 (12认同)
  • 改进可能是将函数转换为生成器,将`means.append`行替换为`yield`.如果`input_list`非常大,这将是更高的内存效率 (3认同)

Maa*_*bré 12

我相信将代码分为两部分.这里将获得滑动窗口,获得前2个元素,并计算平均值.最干净的方法是使用发电机

滑动窗口

使用evamicur的答案略有不同tee,islicezip创建窗口:

def windowed_iterator(iterable, n=2):
    iterators = itertools.tee(iterable, n)
    iterators = (itertools.islice(it, i, None) for i, it in enumerate(iterators))
    yield from zip(*iterators)

windows = windowed_iterator(iterable=a, n=3)
Run Code Online (Sandbox Code Playgroud)
[(3, 5, 2), (5, 2, 7), (2, 7, 5), (7, 5, 3), (5, 3, 6), (3, 6, 8), (6, 8, 4)]
Run Code Online (Sandbox Code Playgroud)

前2个元素

计算你可以使用其他答案中使用的任何方法的2个最高值的平均值,我认为heapqon是最清楚的

from heapq import nlargest
top_n = map(lambda x: nlargest(2, x), windows)
Run Code Online (Sandbox Code Playgroud)

或者等价的

top_n = (nlargest(2, i) for i in windows)
Run Code Online (Sandbox Code Playgroud)
[[5, 3], [7, 5], [7, 5], [7, 5], [6, 5], [8, 6], [8, 6]]
Run Code Online (Sandbox Code Playgroud)

意思

from statistics import mean
means = map(mean, top_n)
Run Code Online (Sandbox Code Playgroud)
[4, 6, 6, 6, 5.5, 7, 7]
Run Code Online (Sandbox Code Playgroud)


dam*_*res 8

以下代码可满足您的需求:

[sum(sorted(a[i:i + 3])[-2:]) / 2 for i in range(len(a) - 2)]
Run Code Online (Sandbox Code Playgroud)

鉴于你的a=[3, 5, 2, 7, 5, 3, 6, 8, 4]回报:

[4.0, 6.0, 6.0, 6.0, 5.5, 7.0, 7.0]
Run Code Online (Sandbox Code Playgroud)


409*_*ict 6

itertools有一个简洁的配方,可以从任何可迭代的项目中提取项目,而不仅仅是可索引的.您可以稍微调整它以提取三胞胎:

def tripletwise(iterable):
    a, b, c = itertools.tee(iterable, 3)
    next(b, None)
    next(itertools.islice(c, 2, 2), None)
    return zip(a, b, c)
Run Code Online (Sandbox Code Playgroud)

使用它,您可以简化迭代所有三元组:

def windowed_means(iterable):
    return [
        (sum(window) - min(window)) / 2.0
        for window in tripletwise(iterable)
    ]
Run Code Online (Sandbox Code Playgroud)