Build a dictionary with single elements or lists as values

Viewed 76

I have a list of dictionaries:

mydict = [
    {'name': 'test1', 'value': '1_1'},
    {'name': 'test2', 'value': '2_1'},
    {'name': 'test1', 'value': '1_2'},
    {'name': 'test1', 'value': '1_3'},
    {'name': 'test3', 'value': '3_1'},
    {'name': 'test4', 'value': '4_1'},
    {'name': 'test4', 'value': '4_2'},
]

I would like to use it to create a dictionary where the values are lists or single values depending of number of their occurrences in the list above. Expected output:

outputdict = {
    'test1': ['1_1', '1_2', '1_3'],
    'test2': '2_1',
    'test3': '3_1',
    'test4': ['4_1', '4_2'],
}

I tried to do it the way below but it always returns a list, even when there is just one value element.

outputdict = {}
outputdict.setdefault(mydict.get('name'), []).append(mydict.get('value'))

The current output is:

outputdict = {
'test1': ['1_1', '1_2', '1_3'],
'test2': ['2_1'],
'test3': ['3_1'],
'test4': ['4_1', '4_2'],

}

2 Answers

Do what you have already done, and then convert single-element lists afterwards:

outputdict = {
    name: (value if len(value) > 1 else value[0])
    for name, value in outputdict.items()
}

You can use a couple of the built-in functions mainly itertools.groupby:

from itertools import groupby
from operator import itemgetter

mydict = [
    {'name': 'test1', 'value': '1_1'},
    {'name': 'test2', 'value': '2_1'},
    {'name': 'test1', 'value': '1_2'},
    {'name': 'test1', 'value': '1_3'},
    {'name': 'test3', 'value': '3_1'},
    {'name': 'test4', 'value': '4_1'},
    {'name': 'test4', 'value': '4_2'},
]

def keyFunc(x):
    return x['name']

outputdict = {}

# groupby groups all the items that matches the returned value from keyFunc
# in our case it will use the names
for name, groups in groupby(mydict, keyFunc):
    # groups will contains an iterator of all the items that have the matched name
    values = list(map(itemgetter('value'), groups))
    
    if len(values) == 1:
        outputdict[name] = values[0]
    else:
        outputdict[name] = values

print(outputdict)

Related