字典列表 - 堆叠字典

时间:2018-02-02 20:09:12

标签: python

在遇到条件时,我无法添加一个字典值,例如我有这个词典列表:

[{'plu': 1, 'price': 150, 'quantity': 2, 'stock': 5},
 {'plu': 2, 'price': 150, 'quantity': 7, 'stock': 10},
 {'plu': 1, 'price': 150, 'quantity': 6, 'stock': 5},
 {'plu': 1, 'price': 200, 'quantity': 4, 'stock': 5},
 {'plu': 2, 'price': 150, 'quantity': 3, 'stock': 10}
]

然后输出应如下所示:

[{'plu': 1, 'price': 150, 'quantity': 8, 'stock': 5},
 {'plu': 1, 'price': 200, 'quantity': 4, 'stock': 5},
 {'plu': 2, 'price': 150, 'quantity': 10, 'stock': 10}
]

只有当plu和price相同时才应该添加数量,它应该忽略key:除此之外的值(例如stock)。最有效的方法是什么?

@edit 我试过了:

import itertools as it
keyfunc = lambda x: x['plu']

groups = it.groupby(sorted(new_data, key=keyfunc), keyfunc)
x = [{'plu': k, 'quantity': sum(x['quantity'] for x in g)} for k, g in groups]

但它只适用于plu,然后我在django中制作html表时只获得数量值,其他都是空的

2 个答案:

答案 0 :(得分:2)

您需要对组合键进行排序/ groupby,而不仅仅是一个键。最简单/最有效的方法is with operator.itemgetter。要保留任意stock值,您需要使用该组两次,因此您需要将其转换为序列:

from operator import itemgetter

keyfunc = itemgetter('plu', 'price')

# Unpack key and listify g so it can be reused
groups = ((plu, price, list(g)) 
          for (plu, price), g in it.groupby(sorted(new_data, key=keyfunc), keyfunc))
x = [{'plu': plu, 'price': price, 'stock': g[0]['stock'],
      'quantity': sum(x['quantity'] for x in g)}
     for plu, price, g in groups]

或者,如果每个唯一stock / plu对的price保证相同,您可以将其包含在key中以简化问题,因此您不需要为这些团体搞砸:

keyfunc = itemgetter('plu', 'price', 'stock')
groups = it.groupby(sorted(new_data, key=keyfunc), keyfunc)
x = [{'plu': plu, 'price': price, 'stock': stock,
      'quantity': sum(x['quantity'] for x in g)
     for (plu, price, stock), g in groups]

或者,您可以在顶层创建getquantity = itemgetter('quantity')(例如keyfunc)并将sum(x['quantity'] for x in g)更改为sum(map(getquantity, g)),这会将工作推送到CPython中的C层,并且可以如果您的团队规模很大,请加快速度。

另一种方法是避免完全排序using collections.Counteror collections.defaultdict(int),尽管Counter会使意图更加明确):

from collections import Counter

grouped = Counter()
for plu, price, stock, quantity in map(itemgetter('plu', 'price', 'stock', 'quantity'), new_data):
    grouped[plu, price, stock] += quantity

然后转换回您的首选表单:

x = [{'plu': plu, 'price': price, 'stock': stock, 'quantity': quantity}
     for (plu, price, stock), quantity in grouped.items()]

对于大型输入,这应该更快,因为它会使用O(n log n) O(n)次操作(大约dict次成本)取代O(1)排序工作。

答案 1 :(得分:1)

使用pandas会使这成为一个微不足道的问题:

import pandas as pd    

data = [{'plu': 1, 'price': 150, 'quantity': 2, 'stock': 5},
        {'plu': 2, 'price': 150, 'quantity': 7, 'stock': 10},
        {'plu': 1, 'price': 150, 'quantity': 6, 'stock': 5},
        {'plu': 1, 'price': 200, 'quantity': 4, 'stock': 5},
        {'plu': 2, 'price': 150, 'quantity': 3, 'stock': 10}]

df = pd.DataFrame.from_records(data)

#    df
#
#       plu  price  quantity  stock
#    0    1    150         2      5
#    1    2    150         7     10
#    2    1    150         6      5
#    3    1    200         4      5
#    4    2    150         3     10

new_df = df.groupby(['plu','price','stock'], as_index=False).sum()
new_df = new_df[['plu','price','quantity','stock']]  # Optional: reorder the columns

#    new_df
#
#       plu  price  quantity  stock
#    0    1    150         8      5
#    1    1    200         4      5
#    2    2    150        10     10

最后,如果您愿意,请将其移回dict(尽管我认为pandas会为您提供更多处理数据元素的功能):

new_data = df2.to_dict(orient='records')

#    new_data
#
#    [{'plu': 1, 'price': 150, 'quantity': 8, 'stock': 5},
#     {'plu': 1, 'price': 200, 'quantity': 4, 'stock': 5},
#     {'plu': 2, 'price': 150, 'quantity': 10, 'stock': 10}]