【问题标题】:Sum dictionary values, using two keys as index: how to achieve this?对字典值求和,使用两个键作为索引:如何实现这一点?
【发布时间】:2021-05-30 07:54:48
【问题描述】:

我有以下字典:

res = [{'name': 'mfi', 'percentage': 100.0, 'tax_base': 1000.0, 'tax_amount': 140.0}, 
{'name': 'serv', 'percentage': 100.0, 'tax_base': 1000.0, 'tax_amount': 140.0}, 
{'name': 'inv', 'percentage': 100.0, 'tax_base': 1200.0, 'tax_amount': 168.0}, 
{'name': 'mfi', 'percentage': 50.0, 'tax_base': 1500.0, 'tax_amount': 210.0}, 
{'name': 'none', 'percentage': 0.0, 'tax_base': 1000.0, 'tax_amount': 0.0}, 
{'name': 'none', 'percentage': 0.0, 'tax_base': 900.0, 'tax_amount': 126.0}, 
{'name': 'mfi', 'percentage': 50.0, 'tax_base': 1000.0, 'tax_amount': 140.0}]

从这本字典中,我需要对 'tax_base' 和 'tax_amount' 值键求和,并使用键 'name' 和 'percentage' 作为索引。

因此,我需要:

res_final = [{'name': 'mfi', 'percentage': 100.0, 'tax_base': 1000.0, 'tax_amount': 140.0},
{'name': 'mfi', 'percentage': 50.0, 'tax_base': 2500.0, 'tax_amount': 350.0},  
{'name': 'serv', 'percentage': 100.0, 'tax_base': 1000.0, 'tax_amount': 140.0}, 
{'name': 'inv', 'percentage': 100.0, 'tax_base': 1200.0, 'tax_amount': 168.0}, 
{'name': 'none', 'percentage': 0.0, 'tax_base': 1900.0, 'tax_amount': 126.0}, 
]

我怎样才能做到这一点?可以给我一个样品吗?

【问题讨论】:

  • 遍历字典,并使用键 namepercentage(可以是元组)创建一个新字典,并使用 tax_basetax_amount 的值创建一个字典,如果它们的条目存在,则添加值。然后就像最后一样,您可以再次遍历字典以将其返回到您想要的形式。上面是一个例子,我想还有更多(可能还有更好的)方法。
  • 我看这个有点长,你也可以把它设为pd.DataFrame 并使用groupby 聚合函数。有关示例,请参见 docs
  • @Thymen,你能给我发一份第一种方法的样本吗?

标签: python-3.x list dictionary indexing key


【解决方案1】:

获取您的原始输入res 和您的首选输出res_final,以下代码将起作用:

# Creating a temporary dictionary with the aggregation
temp_result = {}
for each in res:
    key = (each['name'], each['percentage'])
    if key not in temp_result:
        temp_result[key] = dict(tax_base=0, tax_amount=0)

    temp_result[key]['tax_base'] += each['tax_base']
    temp_result[key]['tax_amount'] += each['tax_amount']

# Transforming the temporary dictionary to the correct format
final_result = []
for (name, percentage), taxes in temp_result.items():
    final_result.append(dict(
            name=name,
            percentage=percentage,
            tax_base=taxes['tax_base'],
            tax_amount=taxes['tax_amount']
    ))

for each in final_result:
    print(each)

结果将是:

{'name': 'mfi', 'percentage': 100.0, 'tax_base': 1000.0, 'tax_amount': 140.0}
{'name': 'serv', 'percentage': 100.0, 'tax_base': 1000.0, 'tax_amount': 140.0}
{'name': 'inv', 'percentage': 100.0, 'tax_base': 1200.0, 'tax_amount': 168.0}
{'name': 'mfi', 'percentage': 50.0, 'tax_base': 2500.0, 'tax_amount': 350.0}
{'name': 'none', 'percentage': 0.0, 'tax_base': 1900.0, 'tax_amount': 126.0}

说明

在第一部分中,我们创建了一个新字典,它以 namepercentage 的组合作为 tuple 的键,并将带有 tax_basetax_amount 的字典作为该键的值.

然后我们检查键是否已经在我们的字典中,如果不是,我们创建键。最后一步是将tax_basetax_amount 相加。

现在我们有了一本包含所有信息的字典,但格式不正确。第二部分负责这一点。我们再次将密钥拆分为namepercentage,并将数据与tax_basetax_amount 合并到一个字典中。


编辑

如果人们想知道如何使用pd.DataFrame

import pandas as pd

df = pd.DataFrame(res)
res = df.groupby(['name', 'percentage'], as_index=False).sum()
final_result = res.to_dict('records')

for each in final_result:
    print(each)

会产生相同的输出,但不保证与输入的顺序相同。

【讨论】:

  • 亲爱的@Thymen,这是按预期工作的。由于订单并不重要,这正是我所需要的。谢谢
【解决方案2】:

这是另一种(非常相似)的方法,但更简洁一些。

在这里,我们首先创建一个唯一的 name:percentage 对列表,然后遍历这些唯一键,从 res 列表中过滤掉与该唯一键不匹配的条目。

unique_keys = list(set([f"{d['name']}:{d['percentage']}" for d in res])) # use list(set()) to keep only unique values as keys
output = []

for key in unique_keys:
    name, percentage = key.split(":")
    matching_entries = list(filter(lambda d: d['name'] == name and str(d['percentage']) == percentage, res))
    
    summed = {"name": name, "percentage": float(percentage), "tax_base": 0.0, "tax_amount": 0.0}
    for entry in matching_entries:
        summed["tax_base"] += entry.get("tax_base", 0) # use get in case value is not in dictionary, 0 is default value
        summed["tax_amount"] += entry.get("tax_amount", 0)
    
    output.append(summed)

output.sort(key=lambda d: d['name']) # sorting to organize a bit

输出:

[{'name': 'inv', 'percentage': 100.0, 'tax_base': 1200.0, 'tax_amount': 168.0},
 {'name': 'mfi', 'percentage': 100.0, 'tax_base': 1000.0, 'tax_amount': 140.0},
 {'name': 'mfi', 'percentage': 50.0, 'tax_base': 2500.0, 'tax_amount': 350.0},
 {'name': 'none', 'percentage': 0.0, 'tax_base': 1900.0, 'tax_amount': 126.0},
 {'name': 'serv', 'percentage': 100.0, 'tax_base': 1000.0, 'tax_amount': 140.0}]

【讨论】:

  • 嗨@djvaroli,也许我在这里遗漏了一些东西。尝试打印 output.sort 时返回 None。 Thymen 的回答解决了我的问题,但无论如何,我想测试你的方法以了解它
  • @pmatos,您得到None 的原因是因为output.sort()in-place 修改,它会更改列表,但不会返回新列表。您可以通过打印output(变量)来打印他的输出。另请参阅this 帖子以获得更详细的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多