Reputation: 537
Say I have the following list:
result = [{"name": "a", "number": 1},
{"name": "a", "number": 2},
{"name": "b", "number": 1},
{"name": "a", "number": 1}]
Can I turn it into something like:
result = [{"name": "a", "number": 1, "count": 2},
{"name": "a", "number": 2},
{"name": "b", "number": 1}]
I tried using the Count class but I couldn't make it work with dictionaries.
Upvotes: 3
Views: 1106
Reputation: 107134
You can use collections.Counter
with list comprehension:
from collections import Counter
[dict(tuple(t) + (('count', c),)) for t, c in Counter(frozenset(d.items()) for d in result).items()]
This returns:
[{'number': 1, 'name': 'a', 'count': 2}, {'number': 2, 'name': 'a', 'count': 1}, {'number': 1, 'name': 'b', 'count': 1}]
Upvotes: 3
Reputation: 22324
The Counter
class relies on your objects being hashable to count them. Thus, a work-around could be to cast your dictionaries to their immutable equivalents.
The immutable equivalent of a dict
is a frozenset
(to account for unorderness of dict
) of tuple
.
You can then count then and form back a list of dictionaries from the counter.
from collections import Counter
result = [{"name": "a", "number": 1},
{"name": "a", "number": 2},
{"name": "b", "number": 1},
{"name": "a", "number": 1}]
frozen_result = map(lambda d: frozenset(d.items()), result)
count = Counter(frozen_result)
new_result = [dict(k, count=v) for k, v in count.items()]
print(new_result)
[{'number': 1, 'name': 'a', 'count': 2},
{'number': 2, 'name': 'a', 'count': 1},
{'name': 'b', 'number': 1, 'count': 1}]
Upvotes: 0
Reputation: 2831
THis will create a empty dictionary with keys from unique elements in result and initialise all default values to 0.
_dict = dict.fromkeys(set([e["name"] for e in result]), 0)
output: {'b': 0, 'a': 0}
This will count the number of element in result for the keys present in _dict.
[_dict.update({element["name"]: _dict[element["name"]]+1}) for element in result]
Since your "number" is same for whole list,
[{"name": key, "number": 1, "count": _dict[key]} for key in _dict.keys()]
output:[{'name': 'b', 'number': 1, 'count': 1},
{'name': 'a', 'number': 1, 'count': 2}]
if number is not same for all the keys, remove all the duplicate dicts from the result list.
no_dups = [i for n, i in enumerate(result) if i not in result[n + 1:]]
output: [{'name': 'b', 'number': 1}, {'name': 'a', 'number': 1}]
create another dict with values as their number :
new = {}
[new.update({i["name"]: i["number"]}) for i in b]
Repeat the last step, like this
[{"name": key, "number": new[key], "count": _dict[key]} for key in _dict.keys()]
Upvotes: 1
Reputation: 164843
One way is to use collections.Counter
to count dictionaries by ('name', 'number')
, then add counts conditional on the count being greater than 1. This can be achieved using a list comprehension:
from collections import Counter
from operator import itemgetter
keys = ('name', 'number')
c = Counter(map(itemgetter(*keys), L))
res = [{**dict(zip(keys, k)), **({'count': v} if v > 1 else {})} \
for k, v in c.items()]
Result:
[{'count': 2, 'name': 'a', 'number': 1},
{'name': 'a', 'number': 2},
{'name': 'b', 'number': 1}]
Upvotes: 0