1131
1131

Reputation: 407

Group values in a list of dictionaries by key

I have a list of dicts like this:

dicts = [
     { "name": "user1", "group": "group1" },
     { "name": "user2", "group": "group2" },
     { "name": "user3", "group": "group1" },
     { "name": "user3", "group": "group3" }
 ]

and I would like to group its elements by their names and create a tuple of the possible groups like:

groupped_dicts = [
     { "name": "user1", "group": "group1" },
     { "name": "user2", "group": "group2" },
     { "name": "user3", "group": ("group1","group3") }
 ]

What I have tried looks like this:

from itertools import groupby
from operator import itemgetter
dicts = sorted(dicts, key=itemgetter('name'))
result = [{
           'username': key,
           'group': "','".join(item['value'] for item in group)
           } for key, group in itertools.groupby(dicts, key=itemgetter('name'))]

Could you help me achieve this?

Upvotes: 0

Views: 105

Answers (2)

Assem
Assem

Reputation: 12107

With small change to output structure:

grouped_dicts = {'user1': ['group1'], 'user2': ['group2'], 'user3': ['group1', 'group3']}

You can do it like:

grouped_dicts = {}
for d in dicts:
    if d['name'] not in grouped_dicts:
        grouped_dicts[d['name']] = []
    grouped_dicts[d['name']].append(d['group'])

Upvotes: 1

norok2
norok2

Reputation: 26946

Although not getting you exactly to your expected output if you were to replace the string join with a comprehension, this would get you to a much closer result:

from itertools import groupby
from operator import itemgetter
dicts = sorted(dicts, key=itemgetter('name'))
result = [{
           'username': key,
           'group': tuple(item['group'] for item in group)
           } for key, group in groupby(dicts, key=itemgetter('name'))]
result
# [{'username': 'user1', 'group': ('group1',)},
#  {'username': 'user2', 'group': ('group2',)},
#  {'username': 'user3', 'group': ('group1', 'group3')}]

However, I would find this an improper use of these data structures. This data would be served much better by a dict:

result = {}
for d in dicts:
    name = d['name']
    group = d['group']
    if name not in result:
        result[name] = []
    result[name].append(group)
print(result)
# {'user1': ['group1'], 'user2': ['group2'], 'user3': ['group1', 'group3']}

which can be later easily converted to what you are after

[{"name": name, "group": tuple(groups) if len(groups) != 1 else groups[0]} for name, groups in result.items()]
# [{'name': 'user1', 'group': 'group1'},
#  {'name': 'user2', 'group': 'group2'},
#  {'name': 'user3', 'group': ('group1', 'group3')}]

Upvotes: 1

Related Questions