2016-01-12 44 views
1

Let's說我有這樣的詞典列表:的Python:合併正字典取決於幾個值+總結

[{'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是相同的,但只有當這些是typeexpense。其他types應該保持原樣。

這樣做的最好方法是什麼?

+0

我看不出你如何能的類型的字典合併到一起。 'amount'是一個數字字段,因此您可以只添加這些值,但其他字段呢? 「account_id_debit」至少有三個不同的值。你將如何挑選合併字典中的其中一個? –

+0

好吧,就是這樣 - 在所有帳號中爲account_id_debit和account_id_credit相同的所有字典添加數值。實際上,「名稱」可以是任何東西,例如第一個字典的值。如果你找到我,那麼可以用聚合進行重複數據刪除。 –

+2

你是否嘗試自己做? – tinySandy

回答

1

您可以聚集通過這些密鑰字典並在需要的地方加上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'}] 
5

一種方法是創建一箇中間的字典,由(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'}] 
+0

你可以用'dict.setdefault'調用來替換'try' /'except'塊,即'd2.setdefault(k,0 ); d2 [k] + = d [「數量」]'。它會削減幾行。 –