views:

187

answers:

6

In Python, I have list of dicts:

dict1 = [{'a':2, 'b':3},{'a':3, 'b':4}]

I want one final dict that will contain the sum of all dicts. I.e the result will be: {'a':5, 'b':7}

N.B: every dict in the list will contain same number of key, value pairs.

+4  A: 

A little ugly, but a one-liner:

dictf = reduce(lambda x, y: dict((k, v + y[k]) for k, v in x.iteritems()), dict1)
carl
actually i have a object list and this dictionary is an object property, have any solution? :(
nazmul hasan
I don't know what you mean?
carl
[ob1, ob2, ob3].. each object has a property data ob1.data it returns a dict {'a':2, 'b':3} like that
nazmul hasan
`dictf = reduce(lambda x, y: dict((k, v + y.data[k]) for k, v in x.data.iteritems()), dict1`
carl
thank you very much :)
nazmul hasan
my code working by this solution ..ok...reduce(lambda x, y: dict((k, v + y.get_local_expenses()[k] if not isinstance(y.get_local_expenses()[k], dict) else 0) for k, v in x.get_local_expenses().iteritems()), glc)
nazmul hasan
@nazmul hasan: Will you understand that in 6 months time? You have written get_local_expenses() 3 times -- is that necessary? What is glc? Have you read @paxdiablo's answer?
John Machin
Perhaps the only good thing about my answer is that it utilizes some cool concepts: reduce, lambda, generator expressions, and iterators.
carl
@John Machin: glc is a list of object get_local_expense() is a property of each object and return a dictionary dictionary value may be another dict or str value or deciamal value.....i have read the @paxdiablo's ans and i solved it before him myself but i like one-liner solution :)
nazmul hasan
+2  A: 

The following code shows one way to do it:

dict1 = [{'a':2, 'b':3},{'a':3, 'b':4}]

final = {}
for k in dict1[0].keys():           # Init all elements to zero.
    final[k] = 0
for d in dict1:
    for k in d.keys():
        final[k] = final[k] + d[k]  # Update the element.

print final

This outputs:

{'a': 5, 'b': 7}

as you desired.

Or, as inspired by kriss, better but still readable:

dict1 = [{'a':2, 'b':3},{'a':3, 'b':4}]

final = {}
for d in dict1:
    for k in d.keys():
        final[k] = final.get(k,0) + d[k]

print final

I pine for the days of the original, readable Python :-)

paxdiablo
You can simplify the first `for` loop to `final={}.fromkeys(dict1[0],0)`. or is that what "readable" is getting at? :)
gnibbler
I could _simplify_ the whole thing into carl's answer but that would mean (1) I may as well delete my answer; and (2) I wouldn't be able to read it next month when I found I needed a small change :-) I should mention that I use Python for teaching (_my_ brand of Python rather than carl's brand). It really is a good language for teaching the basics (sequence, iteration, selection) to kids but, if you're going to whack them over the head with lambdas and such, you may as well teach them F# or Haskell.
paxdiablo
@paxdiablo: for readability, you can fully remove the init loop, just replace `+ d[k]` with `+ res.get(k, 0)`
kriss
That's a good one, @kriss, and still very readable but I think you meant replace `final[k] + d[k]` with `final.get(k,0) + d[k]` - it's the `final` dictionary that I was requiring a default value from if the key didn't exist - I _know_ it esists for `d`.
paxdiablo
@paxdiablo: oups! Yes, your are absolutely right, I inverted dictionnaries.
kriss
@paxdiablo: you may even go one step further (but I wonder for readibality, see by yourself). Replace the inner loop with `final = dict((k, v + final.get(k, 0)) for k, v in d.iteritems())`
kriss
Now it's just starting to look like "Είναι ένα, ένα χιλιόμετρο μακρινός από εδώ" as in useful, but not overly comprehensible (unless you're steeped in the language).
paxdiablo
+2  A: 

This might help:

def sum_dict(d1, d2):
    for key, value in d1.items():
        d1[key] = value + d2.get(key, 0)
    return d1

>>> dict1 = [{'a':2, 'b':3},{'a':3, 'b':4}]
>>> reduce(sum_dict, dict1)
{'a': 5, 'b': 7}
Manoj Govindan
+3  A: 

Leveraging sum() should get better performance when adding more than a few dicts

>>> dict1 = [{'a':2, 'b':3},{'a':3, 'b':4}]
>>> from operator import itemgetter
>>> {k:sum(map(itemgetter(k), dict1)) for k in dict1[0]}        # Python2.7+
{'a': 5, 'b': 7}
>>> dict((k,sum(map(itemgetter(k), dict1))) for k in dict1[0])  # Python2.6
{'a': 5, 'b': 7}

adding Stephan's suggestion

>>> {k: sum(d[k] for d in dict1) for k in dict1[0]}            # Python2.7+
{'a': 5, 'b': 7}
>>> dict((k, sum(d[k] for d in dict1)) for k in dict1[0])      # Python2.6
{'a': 5, 'b': 7}

I think Stephan's version of the Python2.7 code reads really nicely

gnibbler
Is there any reason you use `map` and `itemgetter` instead of list comprehension in the inner loop (i.e. `dict((k, sum(d[k] for d in dict1)) for k in dict1[0])`)?
stephan
@stephan, It used to be faster..seems to be about the same speed now. I'll add it to my answer
gnibbler
Thanks, I didn't know that. +1
stephan
+3  A: 

You can use the collections.Counter

counter = collections.Counter()
for d in dict1: 
    counter.update(d)

Or, if you prefer oneliners:

functools.reduce(operator.add, map(collections.Counter, dict1))
DiggyF
or `sum(map(collections.Counter, dict1),Counter())`. But I am not sure about the relative performance of the functional versions creating all those `Counters()`
gnibbler
This answer demonstrates the golden rule of Python programming: if it comes included with Python don't reinvent the wheel.One point: the final result `counter` is an instance of a subclass of `dict`, if the OP wants a plain `dict` he might add a final `counter = dict(counter)`.
Duncan
A: 

In Python 2.7 you can replace the dict with a collections.Counter object. This supports addition and subtraction of Counters.

Dave Kirby
but its for version 2.7
nazmul hasan