【问题标题】:Python: merge n-dictionaries depending on several values + sumPython:根据几个值+总和合并n个字典
【发布时间】:2016-04-17 16:15:11
【问题描述】:

假设我有一个这样的字典列表:

[{'amount': 42140.0, 'name': 'Payment', 'account_id_credit': 385, 'type': u'expense', 'account_id_debit': 476}, 
{'amount': 43926.0, 'name': 'Payment', 'account_id_credit': 695, 'type': u'payable', 'account_id_debit': 641}, 
{'amount': 3800.0, 'name': 'Payment', 'account_id_credit': 695, 'type': u'expense', 'account_id_debit': 476},
{'amount': 46330.0, 'name': 'Payment', 'account_id_credit': 695, 'type': u'expense', 'account_id_debit': 476}, 
{'amount': 67357.0, 'name': 'Payment', 'account_id_credit': 695, 'type': u'payable', 'account_id_debit': 323},
{'amount': 26441.0, 'name': 'Payment', 'account_id_credit': 695, 'type': u'expense', 'account_id_debit': 476} ... ]

我想将字典合并在一起,以便关键“数量”将是字典中所有 amounts 的总和,其中 account_id_creditaccount_id_debit 相同,但前提是其中 type 是 @ 987654326@。其他types 应保持原样。

最好的方法是什么?

【问题讨论】:

  • 我不明白您如何将这些字典合并在一起。 amount 是一个数字字段,因此您可以将这些值相加,但其他字段呢? account_id_debit 至少有三个不同的值。您将如何选择其中一个用于合并的字典?
  • 嗯,就是这样——在一个字典中为 account_id_debit 和 account_id_credit 相同的所有字典中的金额相加。实际上,“名称”可以是任何东西,例如来自第一个 dict 的值。如果你得到我的话,有点像聚合的重复数据删除。
  • 你自己尝试过吗?
  • 看起来像 pandas.DataFrame 和一些 groupby 的案例

标签: python dictionary merge conditional


【解决方案1】:

一种方法是创建一个中间字典,以 (account_id_credit, account_id_debit) 的元组为键,其中包含总金额值,然后从中构建聚合字典列表:

ld = [{'amount': 42140.0, 'name': 'Payment', 'account_id_credit': 385, 'type': u'expense', 'account_id_debit': 476}, 
{'amount': 43926.0, 'name': 'Payment', 'account_id_credit': 695, 'type': u'payable', 'account_id_debit': 641}, 
{'amount': 3800.0, 'name': 'Payment', 'account_id_credit': 695, 'type': u'expense', 'account_id_debit': 476},
{'amount': 46330.0, 'name': 'Payment', 'account_id_credit': 695, 'type': u'expense', 'account_id_debit': 476}, 
{'amount': 67357.0, 'name': 'Payment', 'account_id_credit': 695, 'type': u'payable', 'account_id_debit': 323},
{'amount': 26441.0, 'name': 'Payment', 'account_id_credit': 695, 'type': u'expense', 'account_id_debit': 476} ]


d2 = {}
for d in ld:
    if d['type'] != 'expense':
        continue
    k = (d['account_id_credit'], d['account_id_debit'])
    try:
        d2[k] += d['amount']
    except KeyError:
        d2[k] = d['amount']

ld2 = []
for d in ld:
    if d['type'] != 'expense':
        ld2.append(d)
        continue
    k = (d['account_id_credit'], d['account_id_debit'])
    try:
        d['amount'] = d2[k]
        # We're done with this amount sum: remove it from the intermediate dict
        del d2[k]
    except KeyError:
        continue
    ld2.append(d)
print ld2

[{'account_id_credit': 385, 'account_id_debit': 476, 'amount': 42140.0, 'type': u'expense', 'name': 'Payment'},
 {'account_id_credit': 695, 'account_id_debit': 641, 'amount': 43926.0, 'type': u'payable', 'name': 'Payment'},
 {'account_id_credit': 695, 'account_id_debit': 476, 'amount': 76571.0, 'type': u'expense', 'name': 'Payment'},
 {'account_id_credit': 695, 'account_id_debit': 323, 'amount': 67357.0, 'type': u'payable', 'name': 'Payment'}]

【讨论】:

  • 您可以将开头的 try/except 块替换为 dict.setdefault 调用,即 d2.setdefault(k, 0); d2[k] += d["amount"]。它会减少几行。
【解决方案2】:

您可以通过这些键聚合字典,并在需要时对 amount 变量求和。

dicts = [{'amount': 42140.0, 'name': 'Payment', 'account_id_credit': 385, 'type': u'expense', 'account_id_debit': 476}, 
         {'amount': 43926.0, 'name': 'Payment', 'account_id_credit': 695, 'type': u'payable', 'account_id_debit': 641}, 
         {'amount': 3800.0, 'name': 'Payment', 'account_id_credit': 695, 'type': u'expense', 'account_id_debit': 476},
         {'amount': 46330.0, 'name': 'Payment', 'account_id_credit': 695, 'type': u'expense', 'account_id_debit': 476}, 
         {'amount': 67357.0, 'name': 'Payment', 'account_id_credit': 695, 'type': u'payable', 'account_id_debit': 323},
         {'amount': 26441.0, 'name': 'Payment', 'account_id_credit': 695, 'type': u'expense', 'account_id_debit': 476}]


def aggregate(dicts, keys):
    def worker(aggr, dic):
        key_vals = tuple(dic[key] for key in keys)
        aggr.setdefault(key_vals, {key: [] for key in dic.iterkeys()})
        for key, value in dic.iteritems():
            aggr[key_vals][key].append(value)
        return aggr

    assert len(set(tuple(dic.iterkeys()) for dic in dicts)) == 1
    return reduce(worker, dicts, {})


keys = ("account_id_credit", "type", "account_id_debit")
aggr_expense = [dic for keys, dic in aggregate(dicts, keys).iteritems() if keys[1] == u"expense"]
merged_expense = [{key: sum(value) if key == "amount" else value[0] for key, value in dic.iteritems()}
                  for dic in aggr_expense]
result = merged_expense + filter(lambda dic: dic["type"] != u"expense", dicts)
print(result)

输出:

[{'account_id_credit': 695, 'account_id_debit': 476, 'amount': 76571.0, 'type': u'expense', 'name': 'Payment'},
 {'account_id_credit': 385, 'account_id_debit': 476, 'amount': 42140.0, 'type': u'expense', 'name': 'Payment'},
 {'account_id_credit': 695, 'account_id_debit': 641, 'amount': 43926.0, 'type': u'payable', 'name': 'Payment'}, 
 {'account_id_credit': 695, 'account_id_debit': 323, 'amount': 67357.0, 'type': u'payable', 'name': 'Payment'}]

【讨论】:

    猜你喜欢
    • 2019-05-15
    • 2021-03-14
    • 2021-09-17
    • 2021-12-28
    • 2016-01-20
    • 1970-01-01
    • 1970-01-01
    • 2020-07-21
    • 2018-04-16
    相关资源
    最近更新 更多