Was ist die pythonischste Methode, um eine Liste von Diktaten zu erstellen und alle Werte für übereinstimmende Schlüssel aus jeder Zeile in der Liste zusammenzufassen?

Ich habe das getan, aber ich vermute, dass ein Verständnis mehr pythonisch ist:

from collections import defaultdict
demandresult = defaultdict(int)   # new blank dict to store results 
for d in demandlist:
    for k,v in d.iteritems():
        demandresult[k] = demandresult[k] + v

In Python - Summenwerte im Wörterbuch betraf die Frage immer denselben Schlüssel, aber In meinem Fall ist der Schlüssel in jeder Zeile möglicherweise ein neuer Schlüssel, der noch nie zuvor gefunden wurde.

2
Mark Ginsburg 18 Apr. 2018 im 03:12

4 Antworten

Beste Antwort

Ich denke, dass Ihre Methode ziemlich pythonisch ist. Verständnis ist nett, aber sie sollten nicht wirklich übertrieben werden, und sie können zu wirklich chaotischen Einzeilern führen, wie dem folgenden :).

Wenn Sie auf einem Diktat bestehen:

demand_list = [{u'2018-04-29': 1, u'2018-04-30': 1, u'2018-05-01': 1}, 
               {u'2018-04-21': 1},
               {u'2018-04-18': 1, u'2018-04-19': 1, u'2018-04-17' : 1}]

d = {key:sum(i[key] for i in demand_list if key in i) 
     for key in set(a for l in demand_list for a in l.keys())}

print(d)
>>>{'2018-04-21': 1, '2018-04-17': 1, '2018-04-29': 1, '2018-04-30': 1, '2018-04-19': 1, '2018-04-18': 1, '2018-05-01': 1}
2
Primusa 18 Apr. 2018 im 01:23

Das einzige, was in Ihrem Code unklar schien, war die Double-for-Loop. Es kann klarer sein, das demandlist in eine flache Iteration zu reduzieren - dann präsentiert der Loopant die Logik so einfach wie möglich. Erwägen:

demandlist = [{
    u'2018-04-29': 1,
    u'2018-04-30': 1,
    u'2018-05-01': 1
}, {
    u'2018-04-21': 1
}, {
    u'2018-04-18': 1,
    u'2018-04-19': 1,
    u'2018-04-17': 1
}]

import itertools as it
from collections import defaultdict

demandresult = defaultdict(int)

for k, v in it.chain.from_iterable(map(lambda d: d.items(), demandlist)):
    demandresult[k] = demandresult[k] + v

(Damit druckt print(demandresult) defaultdict(<class 'int'>, {'2018-04-29': 1, '2018-04-30': 1, '2018-05-01': 1, '2018-04-21': 1, '2018-04-18': 1, '2018-04-19': 1, '2018-04-17': 1}).)

Wenn ich mir vorstelle, dies zum ersten Mal (oder einige Monate später) zu lesen, kann ich mir vorstellen: "Ok, ich kollabiere demandlist zu einem iterierbaren Schlüsselwert, es ist mir egal, wie und dann Summieren der Werte der übereinstimmenden Schlüssel. "

Es ist bedauerlich, dass ich dort map benötige, um sicherzustellen, dass die endgültige Iterable Schlüssel-Wert-Paare enthält. it.chain.from_iterable(demandlist) ist eine Nur-Schlüssel-Iterierbarkeit, daher muss ich bei jedem Diktat items aufrufen.

Beachten Sie, dass diese Implementierung (wie Ihre!) Im Gegensatz zu vielen der vorgeschlagenen Antworten die Anzahl der Scans über die Daten auf nur einen minimiert - Leistungsgewinn (und ich versuche, so viele einfache Leistungsgewinne wie möglich zu erzielen).

0
Ahmed Fasih 18 Apr. 2018 im 00:57

Hier ist ein weiterer Einzeiler (ab-), der collections.ChainMap verwendet, um die kombinierten Schlüssel zu erhalten:

>>> from collections import ChainMap
>>> {k: sum(d.get(k, 0) for d in demand_list) for k in ChainMap(*demand_list)}
{'2018-04-17': 1, '2018-04-21': 1, '2018-05-01': 1, '2018-04-30': 1, '2018-04-19': 1, '2018-04-29': 1, '2018-04-18': 1}

Dies ist leicht die langsamste der hier vorgeschlagenen Methoden.

1
Paul Panzer 18 Apr. 2018 im 01:28

Ich nehme an, Sie möchten eine Liste der summierten Werte jedes Wörterbuchs zurückgeben.

list_of_dict = [
    {'a':1, 'b':2, 'c':3},
    {'d':4, 'e':5, 'f':6}
]

sum_of_each_row = [sum(v for v in d.values()) for d in list_of_dict] # [6,15]

Wenn Sie die Gesamtsumme zurückgeben möchten, setzen Sie einfach sum () in "sum_of_each_row".

BEARBEITEN:

Das Hauptproblem besteht darin, dass Sie nicht für jeden Schlüssel einen Standardwert haben. Sie können daher die Methode dict.setdefault () verwenden, um den Standardwert festzulegen, wenn ein neuer Schlüssel vorhanden ist.

list_of_dict = [
    {'a':1, 'b':1},
    {'b':1, 'c':1},
    {'a':2}
]

d = {}
d = {k:d[k]+v if k in d.keys() else d.setdefault(k,v)
    for row in list_of_dict for k,v in row.items()} # {'a':3, 'b':2, 'c':1}
0
K.Marker 18 Apr. 2018 im 01:30