在Python中平均多个不同长度列表的最快方法

时间:2016-04-22 14:18:51

标签: python mongodb

所以我有一些列出了来自Mongo的预先计算的值(商店的产品价格平均值)。每个列表代表不同产品的一周。列表可以具有不同的大小,因为有时产品不会在一周内销售。商店的平均子列表在两个不同的星期之间也可以是不同的大小,因为某些商店可能缺货(因此该产品没有任何价格)。

有没有办法获得我的结果而不需要多次for循环?

这是一个有两周时间澄清的例子:

Week1

[{u'_id': 193390, u'avgT': 12, u'avgByS': [{u'S': 7, u'avg': 12}]}, {u'_id': 193396, u'avgT': 29, u'avgByS': [{u'S': 7, u'avg': 29}, {u'S': 5, u'avg': 29}]}]

Week2

[{u'_id': 193390, u'avgT': 11, u'avgByS': [{u'S': 7, u'avg': 10}, {u'S': 9, u'avg': 12}]}, {u'_id': 193398, u'avgT': 15, u'avgByS': [{u'S': 7, u'avg': 29}, {u'S': 5, u'avg': 29}]},{u'_id': 193396, u'avgT': 29, u'avgByS': [{u'S': 7, u'avg': 29}, {u'S': 5, u'avg': 29}]}]

期望输出

[{u'_id': 193390, u'avgT': 11.5, u'avgByS': [{u'S': 7, u'avg': 11}, {u'S': 9, u'avg': 12}]}, {u'_id': 193398, u'avgT': 15, u'avgByS': [{u'S': 7, u'avg': 29}, {u'S': 5, u'avg': 29}]},{u'_id': 193396, u'avgT': 29, u'avgByS': [{u'S': 7, u'average': 29}, {u'S': 5, u'average': 29}]}]

1 个答案:

答案 0 :(得分:0)

  

有没有办法获得我的结果而不需要多次for循环?

没有。您的数据结构是列表内的列表。没有...迭代就无法迭代数据。

但嵌套for循环并不总是一个坏主意!一些嵌套的for循环导致O(N ^ 2)行为,但是一些嵌套for循环会导致O(N)行为,这取决于你的实际代码。

以下是计算数据的一种方法。请注意,它有三个嵌套for循环。你无法避免这种情况。但是没有一个嵌套循环导致多项式复杂性。我在big-O上生锈,但我声称以下程序中的聚合循环在O(N)中运行,其中N是avgByS列表中的值的总数。 (第二个循环的复杂性将等于第一个循环,但我在结果上调用sorted()。这可能会减慢一些。)

from __future__ import division
from pprint import pprint

weeks = [
    [{u'_id': 193390, u'avgT': 12, u'avgByS': [{u'S': 7, u'avg': 12}]}, {u'_id': 193396, u'avgT': 29, u'avgByS': [{u'S': 7, u'avg': 29}, {u'S': 5, u'avg': 29}]}],
    [{u'_id': 193390, u'avgT': 11, u'avgByS': [{u'S': 7, u'avg': 10}, {u'S': 9, u'avg': 12}]}, {u'_id': 193398, u'avgT': 15, u'avgByS': [{u'S': 7, u'avg': 29}, {u'S': 5, u'avg': 29}]},{u'_id': 193396, u'avgT': 29, u'avgByS': [{u'S': 7, u'avg': 29}, {u'S': 5, u'avg': 29}]}]
]

# First, accumlate the data. Convert lists to dicts.
total = {}
for week in weeks:
    for product in week:
        total_product = total.setdefault(
            product['_id'],
            {
                u'_id':product['_id'],
                u'avgT':[],
                u'avgByS':{}
            })
        total_product['avgT'].append(product['avgT'])
        for store in product['avgByS']:
            total_product['avgByS'].setdefault(store['S'],[]).append(store['avg'])
pprint (total)

# Next, convert dicts to lists and compute averages.
averages = [{
    u'_id': k,
    u'avgT': sum(v['avgT'])/len(v['avgT']),
    u'avgByS': [{
        u'S': kk,
        u'avg': sum(vv)/len(vv),
        }
        for kk,vv in sorted(v['avgByS'].items())]
    }
    for k,v in sorted(total.items())]
pprint(averages)