0

I got the following list of dicts

list_of_dicts = [
                {'product': 'car', 'city': 'new york', 'quantity': 13},
                {'product': 'car', 'city': 'new york', 'quantity': 25},
                {'product': 'bus', 'city': 'miami', 'quantity': 5},
                {'product': 'container', 'city': 'atlanta', 'quantity' 5},
                {'product': 'container', 'city': 'atlanta', 'quantity' 8}
            ]

My target is, when values of 'product' and 'city' are the same, sum up the values of 'quantity'. The result should look like this:

result_list_of_dicts = [
                {'product': 'car', 'city': 'new york', 'quantity': 38},
                {'product': 'bus', 'city': 'miami', 'quantity': 5},
                {'product': 'container', 'city': 'atlanta', 'quantity' 13},
            ]

Is there a pythonic way? I tried a couple of things but I better not show them because they are really ugly.

Thank you in advance!

buxxxbaum
  • 65
  • 6

4 Answers4

3

You can do the following, using only standard library utils:

from operator import itemgetter
from functools import reduce
from itertools import groupby

pc = itemgetter("product", "city")  # sorting and grouping key
q = itemgetter("quantity")
combine = lambda d1, d2: {**d1, "quantity": q(d1) + q(d2)}

[reduce(combine, g) for _, g in groupby(sorted(list_of_dicts, key=pc), key=pc)]
# [{'product': 'bus', 'city': 'miami', 'quantity': 5}, 
#  {'product': 'car', 'city': 'new york', 'quantity': 38}, 
#  {'product': 'container', 'city': 'atlanta', 'quantity': 13}]

Or, maybe even simpler and linear:

from collections import Counter

pc = itemgetter("product", "city") 
q = itemgetter("quantity")

totals = Counter()
for dct in list_of_dicts:
    totals[pc(dct)] += q(dct)

result_list_of_dicts = [
    {"product": p, "city": c, "quantity": q} for (p, c), q in totals.items()
]
user2390182
  • 72,016
  • 6
  • 67
  • 89
2

One approach using collections.Counter

from collections import Counter

list_of_dicts = [
    {'product': 'car', 'city': 'new york', 'quantity': 13},
    {'product': 'car', 'city': 'new york', 'quantity': 25},
    {'product': 'bus', 'city': 'miami', 'quantity': 5},
    {'product': 'container', 'city': 'atlanta', 'quantity': 5},
    {'product': 'container', 'city': 'atlanta', 'quantity': 8}
]

counts = sum((Counter({(d["product"], d["city"]): d["quantity"]}) for d in list_of_dicts), Counter())
result = [{"product": product, "city": city, "quantity": quantity} for (product, city), quantity in counts.items()]
print(result)
Dani Mesejo
  • 61,499
  • 6
  • 49
  • 76
1

A pandas implementation

Group by "product" and "city", sum over the groups and reset index to get original columns.

import pandas as pd

list_of_dicts = [
    {'product': 'car', 'city': 'new york', 'quantity': 13},
    {'product': 'car', 'city': 'new york', 'quantity': 25},
    {'product': 'bus', 'city': 'miami', 'quantity': 5},
    {'product': 'container', 'city': 'atlanta', 'quantity': 5},
    {'product': 'container', 'city': 'atlanta', 'quantity': 8}
]

df = pd.DataFrame(list_of_dicts)
print(df)
df = df.groupby(["product", "city"]).sum().reset_index()
print(df)
summed_dict = df.to_dict("records")
print(summed_dict)
Tzane
  • 2,752
  • 1
  • 10
  • 21
0

You could do it with a loop, initializing it the first time you encounter the product.

list_of_dicts = [
    {'product': 'car', 'city': 'new york', 'quantity': 13},
    {'product': 'car', 'city': 'new york', 'quantity': 25},
    {'product': 'bus', 'city': 'miami', 'quantity': 5},
    {'product': 'container', 'city': 'atlanta', 'quantity': 5},
    {'product': 'container', 'city': 'atlanta', 'quantity': 8}
]

new_dict = {}
for ld in list_of_dicts:
    if ld['product'] not in new_dict:
        new_dict[ld['product']] = {}
        new_dict[ld['product']]['city'] = ld['city']
        new_dict[ld['product']]['quantity'] = 0
    new_dict[ld['product']]['quantity'] += ld['quantity']

# print(new_dict)
# {'car': {'city': 'new york', 'quantity': 38}, 'bus': {'city': 'miami', 'quantity': 5}, 'container': {'city': 'atlanta', 'quantity': 13}}

result_list_of_dicts = [{'product': nd,
                         'city': new_dict[nd]['city'],
                         'quantity': new_dict[nd]['quantity']} for nd in new_dict]
# print(result_list_of_dicts)
# [{'product': 'car', 'city': 'new york', 'quantity': 38}, {'product': 'bus', 'city': 'miami', 'quantity': 5}, {'product': 'container', 'city': 'atlanta', 'quantity': 13}]

scmanjarrez
  • 407
  • 4
  • 8