So, pythonists, what’s the elegant answer?
So, pythonists, what’s the elegant answer?
d = collections.defaultdict(int)
for item in mylist:
d[item["thing"]] += item["count"]
newlist = [{"thing": key, "count": value} for key, value in d.items()]
(I'm assuming the order doesn't matter, and the specific output format is needed. E.g. if the next step then iterates over that list and unpacks it, obviously get rid of the last line and use the dict)There is the collections.Counter type, but I think there's not really a beneficial way of using that here.
Generally, the "there is one elegant solution" aspect of Python is widely overstated :D
I really thought if this was possible to do in a single dictionary comprehension, with some kind of d = {k: sum(v) for k, v in <something>}, but whatever goes in <something> ends up being super ugly.
[{"thing": k, "count": v} for k, v in [[c, c.update({x["thing"]: x["count"]})] for c in [Counter()] for x in response][0][0].items()]
SELECT a, b, SUM(c) FROM table GROUP BY a
doesn't even compile. You either project away `b` or group over both `a` and `b`. groups = itertools.groupby(sorted(mylist, key=lambda x: x['thing']), key=lambda x: x['thing'])
newlist = [{**group[0], 'count': sum(item['count'] for item in group)} for group in groups]
I'm not overly fond of it, having to sort the list for `groupby` is unpleasant and extracting values from dictonaries is verbose. If this was an array of tuples it could be made much more concise, but of course that doesn't allow storing extra information for each thing, which this solution does. def merge_counts(mylist):
thing_lookup = {} # map thing -> item
newlist = []
for item in mylist:
thing = item["thing"]
if thing in thing_lookup:
# seen before; update count.
thing_lookup[thing]["count"] += item["count"]
else:
# first time I've seen this thing
newlist.append(item)
thing_lookup[thing] = item
return newlist
It, like the original, mutates the original dictionary. I would prefer: # first time I've seen this thing
thing = thing.copy() # don't mutate the original
newlist.append(item)In javascript:
const mylist = [
{'thing': 'A', 'count': 4},
{'thing': 'B', 'count': 2},
{'thing': 'A', 'count': 6}];
const dict = mylist.reduce(({thing, count}, dict) => ({
[thing] : dict[thing] ? dict[thing]+count : count
}, {});
const newList = Object.keys(dict).map(thing => { thing, count: dict[thing] });
(Not tested or anything, so no guarantee that this works right off the bat, but something like this should work.) from functools import reduce
result = [
{'thing': k, 'count': v}
for k, v in reduce(
lambda result, item: {
**result,
item['thing']: item['count'] + result.get(item['thing'], 0)
},
mylist,
{}
).items()
] agg = {}
for item in mylist:
if item['thing'] in agg:
agg[item['thing']] += item['count']
else:
agg[item['thing']] = item['count']
result_list = []
for key, value in agg.items():
result_list.append(dict(thing=key, count=value))
In beginner land, reduce makes your eyes glaze over and dict.get(key, default) is understandable in principle but still confusing in practice.Edit: upon further reflection I think my application is at the tipping point where it needs another database table.
I can’t really remember it, so I’d probably go with defaultdict