Reputation: 323
I have a list that contains dictionaries like this:
list1 = [{'name': 'bob', 'email': '[email protected]', 'address': '123 house lane',
'student_id': 12345}, {'name': 'steve', 'email': '[email protected]',
'address': '456 house lane', 'student_id': 34567}, {'name': 'bob',
'email': '[email protected]', 'address': '789 house lane', 'student_id': 45678}]
Is there a way in python to group selected key, values pairs within a new dictionary based on 'name' value? For instance, something like this as an end result:
new_list = [
{'name': 'bob',
{'emails': ['[email protected]',
'[email protected]']},
{'address': ['123 house lane',
'789 house lane']},
{'name': 'steve',
{'email': ... },
{'address': ... }}
# let's assume the list1 has various entries at some point
# which may or may not have duplicate 'name' values
# and new_list will hold the groupings
]
Upvotes: 0
Views: 927
Reputation: 691
The code below gives you nested dictionaries. Nested dictionaries give you faster processing to find the key while in list you have to create a loop.
list1 = [{'name': 'bob', 'email': '[email protected]', 'address': '123 house lane',
'student_id': 12345}, {'name': 'steve', 'email': '[email protected]',
'address': '456 house lane', 'student_id': 34567}, {'name': 'bob',
'email': '[email protected]', 'address': '789 house lane', 'student_id': 45678}]
dict1 = {}
for content in list1:
if content['name'] in [name for name in dict1]:
dict1[content['name']] = {'emails': dict1[content['name']]['emails'] + [content['address']], 'addresses': dict1[content['name']]['addresses'] + [content['email']]}
else:
dict1[content['name']] = {'emails': [content['email']], 'addresses': [content['address']]}
print dict1
Output of the code is
{'steve': {'emails': ['[email protected]'], 'addresses': ['456 house lane']}, 'bob': {'emails': ['[email protected]', '789 house lane'], 'addresses': ['123 house lane', '[email protected]']}}
Upvotes: 1
Reputation: 54163
Sounds like this is what you want to do:
list1 = [{'name': 'bob', 'email': '[email protected]',
'address': '123 house lane', 'student_id': 12345},
{'name': 'steve', 'email': '[email protected]',
'address': '456 house lane', 'student_id': 34567},
{'name': 'bob', 'email': '[email protected]',
'address': '789 house lane', 'student_id': 45678}]
import operator
list1.sort(key=operator.itemgetter('name'))
new_list = []
for studentname, dicts in itertools.groupby(list1, operator.itemgetter('name')):
d = {'name': studentname}
for dct in dicts:
for key,value in dct.items():
if key == 'name':
continue
d.setdefault(key, []).append(value)
new_list.append(d)
DEMO:
[{'address': ['123 house lane', '789 house lane'],
'email': ['[email protected]', '[email protected]'],
'name': 'bob',
'student_id': [12345, 45678]},
{'address': ['456 house lane'],
'email': ['[email protected]'],
'name': 'steve',
'student_id': [34567]}]
If you were going to use this extensively you should probably hard-code some better names (addresses
instead of address
for instance) and make a mapping that populates them for you.
keys_mapping = {'address': 'addresses',
'email': 'emails',
'student_id': 'student_ids'}
for studentname, dicts in itertools.groupby(list1, operator.itemgetter('name')):
d = {'name': studentname}
for dct in dicts:
for key,value in dct_items():
new_key = keys_mapping.get(key,key)
# get the updated value if it's defined, else give `key`
d.setdefault(new_key, []).append(value)
new_list.append(d)
Upvotes: 2