Python itertools.groupby 具有多个值的字典

Python itertools.groupby with dictionaries with multiple values

我正在尝试使用 Python itertools.groupby 函数来更改此列表:

items = [
  {'price': 5.0, 'name': 'Strawberries'}, 
  {'price': 5.0, 'name': 'Strawberries'}, 
  {'price': 5.0, 'name': 'Strawberries'}, 
  {'price': 11.23, 'name': 'Coffee'}, 
  {'price': 11.23, 'name': 'Coffee'}, 
  {'price': 3.11, 'name': 'Green Tea'}
]

进入这个:

{
  'Strawberries': {'price': 5.0, 'quantity': 3}, 
  'Coffee': {'price': 11.23, 'quantity': 2}, 
  'Green Tea': {'price': 3.11, 'quantity': 1}
}

我都试过了:

grouped = { 
  name: {
    'price': list(article)[0]['price'], 
    'quantity': len(list(article))
  } for name, article in groupby(items, key=lambda x: x['name']) 
}

和:

grouped = { 
  name: {
    'quantity': list(article), 
    'price': list(article)[0]['price']
  } for name, article in groupby(items, key=lambda x: x['name']) 
}

结果如下:

{
  'Strawberries': {'price': 5.0, 'quantity': []}, 
  'Coffee': {'price': 11.23, 'quantity': []}, 
  'Green Tea': {'price': 3.11, 'quantity': []}
}

IndexError: list index out of range

我不确定为什么我只能访问我尝试创建的子字典中的一个值的文章。

如有任何建议,我们将不胜感激。 谢谢!

在我看来,这不是 groupby 的最佳用例。在 items.

上循环构建 (default)dict 更容易
from collections import defaultdict

result = defaultdict(lambda: {'price': None, 'quantity': 0})

for item in items:
    subdict = result[item['name']]
    subdict['quantity'] += 1
    subdict['price'] = item['price']

输出:

>>> result
defaultdict(<function __main__.<lambda>()>,
            {'Strawberries': {'price': 5.0, 'quantity': 3},
             'Coffee': {'price': 11.23, 'quantity': 2},
             'Green Tea': {'price': 3.11, 'quantity': 1}})

(如果价格被商品的最后一次看到的价格覆盖。如果您不希望具有相同名称的商品的价格不明确,这是可以的。)

编辑:没有 defaultdict

result = {}
for item in items:
    result.setdefault(item['name'], {'price': item['price'], 'quantity': 0})['quantity'] += 1  

您得到空白列表或索引错误的原因是因为您的 article 对象是一个迭代器,它在第一次调用 list(article) 时被完全消耗。

当你第一次拿到价格时,价格是正确的,但数量是空的,因为你已经消费了article。相比之下,当您先获取数量然后获取第一个项目的价格时,第二次调用 list(article) 会生成一个空列表,您尝试对其进行索引但不能,因为没有项目。

这是 groupby 的解决方案,您可以在其中保存 list(article) 并将其用于价格和数量。

grouped = {}
for name, article in groupby(items, key=lambda itm: itm["name"]):
    products = list(article)
    grouped[name] = {
        "price": products[0]["price"],
        "quantity": len(products),
    }

编辑:如评论中所述,这假定您的 items 列表按照您想要的顺序排列。通常您会希望以有意义的方式对传递给 groupby() 的可迭代对象进行排序。但也许您只是想将连续的项目组合在一起,即使相同的项目出现在列表的后面。