so I need an optimal method for creating a list of dicts in python.

So I have a list that looks like this:

[
   {'name': 'John', 'hobbies': ['Reading', 'Swimming']},
   {'name': 'Gina', 'hobbies': ['Skating', 'Cooking']},
   {'name': 'John', 'hobbies': ['Gardening', 'Swimming']}
]

So I need the output to be like this:

[
   {'name': 'John', 'hobbies': ['Reading', 'Swimming', 'Gardening']},
   {'name': 'Gina', 'hobbies': ['Skating', 'Cooking']},
]

As you can can see, I need to create a set of hobbies for every name, and indeed create a unique list of dicts.

This is what I have tried:

{v['_id']['route']: v for v in routes_list}.values()

But it doesn't take care of creating a set

Can anyone please help me out with the doing so in the most optimal way?

Thank you.

2 Answers

1
Paritosh Singh On Best Solutions

Just construct an intermediate default dictionary, which enables you to do this in linear time. Convert back to desired structure at the end.

inp = [
   {'name': 'John', 'hobbies': ['Reading', 'Swimming']},
   {'name': 'Gina', 'hobbies': ['Skating', 'Cooking']},
   {'name': 'John', 'hobbies': ['Gardening', 'Swimming']}
]

from collections import defaultdict
temp = defaultdict(set)
for d in inp:
    temp[d['name']].update(d['hobbies'])

result = [{'name':k, 'hobbies': list(v)} for k, v in temp.items()]

Output:

[{'name': 'John', 'hobbies': ['Gardening', 'Reading', 'Swimming']},
 {'name': 'Gina', 'hobbies': ['Cooking', 'Skating']}]
1
DeepSpace On

If you agree to change the structure of the output to just a dictionary from a name to a hobbies set this can be done in linear time (ignoring edge cases, ie a lot of hash collisions):

from collections import defaultdict

data = [
    {'name': 'John', 'hobbies': ['Reading', 'Swimming']},
    {'name': 'Gina', 'hobbies': ['Skating', 'Cooking']},
    {'name': 'John', 'hobbies': ['Gardening', 'Swimming']}
]

output = defaultdict(set)

for d in data:
    output[d['name']].update(d['hobbies'])

print(output)
# defaultdict(<class 'set'>, {'John': {'Reading', 'Swimming', 'Gardening'},
#                             'Gina': {'Cooking', 'Skating'}})

If you insist on using a list of dicts you can still achieve almost linear time (a list lookup is still O(n)) but with a logic to map indices to names:

data = [
        {'name': 'John', 'hobbies': ['Reading', 'Swimming']},
        {'name': 'Gina', 'hobbies': ['Skating', 'Cooking']},
        {'name': 'John', 'hobbies': ['Gardening', 'Swimming']}
    ]

output = []
names_to_indices = {}
for d in data:
    if d['name'] not in names_to_indices:
        output.append({'name': d['name'], 'hobbies': d['hobbies']})
        names_to_indices[d['name']] = len(output) - 1
    else:
        index = names_to_indices[d['name']]
        for hobbie in d['hobbies']:
            if hobbie not in output[index]['hobbies']:
                output[index]['hobbies'].append(hobbie)
print(output)
# [{'name': 'John', 'hobbies': ['Reading', 'Swimming', 'Gardening']},
#  {'name': 'Gina', 'hobbies': ['Skating', 'Cooking']}]

You can make this a truly linear time (again, if we ignore the possibility of excessive hash collisions) if you agree for hobbies to be a set:

data = [
        {'name': 'John', 'hobbies': ['Reading', 'Swimming']},
        {'name': 'Gina', 'hobbies': ['Skating', 'Cooking']},
        {'name': 'John', 'hobbies': ['Gardening', 'Swimming']}
    ]

output = []
names_to_indices = {}
for d in data:
    if d['name'] not in names_to_indices:
        output.append({'name': d['name'], 'hobbies': set(d['hobbies'])})
        names_to_indices[d['name']] = len(output) - 1
    else:
        index = names_to_indices[d['name']]
        output[index]['hobbies'].update(d['hobbies'])
print(output)
# [{'name': 'John', 'hobbies': {'Gardening', 'Swimming', 'Reading'}},
#  {'name': 'Gina', 'hobbies': {'Skating', 'Cooking'}}]