Reputation: 264
I have:
[
{'id': 1, 'name': 'foo'},
{'id': 2, 'name': 'bar'},
{'id': 1, 'name': 'gesiel'}
]
I want:
{
1: [
{'id': 1, 'name': 'foo'},
{'id': 1, 'name': 'gesiel'}
],
2: [
{'id': 2, 'name': 'bar'}
]
}
This code does this:
organized = {d['id']:[] for d in data}
[organized[d['id']].append(d) for d in data]
Is there a more pythonic way to do this?
Upvotes: 4
Views: 225
Reputation: 3801
Austin's answer is better, but here method just using dict
s
In [175]: data = [{'id': 1, 'name': 'foo'}, {'id': 2, 'name': 'bar'}, {'id': 1, 'name': 'gesiel'}]
In [176]: organised = {}
In [177]: for d in data:
...: if d['id'] in organised:
...: organised[d['id']].append(d)
...: else:
...: organised[d['id']] = [d]
...:
In [178]: organised
Out[178]:
{1: [{'id': 1, 'name': 'foo'}, {'id': 1, 'name': 'gesiel'}],
2: [{'id': 2, 'name': 'bar'}]}
Upvotes: 0
Reputation: 164693
There is nothing wrong with a 2-pass O(n) solution if you are, as here, working with an in-memory object. The main issue with your code is you are misusing the list comprehension.
A list comprehension should be used to construct a new list, not to process an in-place function or method in a loop. Taking your example, your logic will create a list which looks like:
[None, None, None, ..., None]
The side-effect of the comprehension means that organized
values have items appended to them as required. Instead, you can rewrite using a simple for
loop:
organized = {d['id']: [] for d in data}
for d in data:
organized[d['id']].append(d)
Your logic can be made more efficient by not adding keys via an initial iteration. This common problem is resolved by collections.defaultdict
, as in @Austin's solution. This solution gives an empty list for any key which does not exist:
from collections import defaultdict
res = defaultdict(list)
for d in data:
res[d['i']].append(d)
print(res)
defaultdict(list,
{1: [{'id': 1, 'name': 'foo'}, {'id': 1, 'name': 'gesiel'}],
2: [{'id': 2, 'name': 'bar'}]})
Since defaultdict
is a subclass of dict
, there's usually no need to convert this back to a regular dictionary.
Upvotes: 0
Reputation: 4606
Using groupby.itertools we can create this dicitonary
from itertools import groupby
lista = [{'id': 1, 'name': 'foo'}, {'id': 2, 'name': 'bar'}, {'id': 1, 'name': 'gesiel'}]
d = {}
for k, g in groupby(sorted(lista, key=lambda x: x['id']), key=lambda x: x['id']):
d[k] = list(g)
# {1: [{'id': 1, 'name': 'foo'}, {'id': 1, 'name': 'gesiel'}], 2: [{'id': 2, 'name': 'bar'}]}
or using dictionary comprehension
d = {k: list(g) for k, g in groupby(sorted(lista, key=lambda x: x['id']), key=lambda x: x['id'])}
Upvotes: 0
Reputation: 26039
from collections import defaultdict
data = [{'id': 1, 'name': 'foo'}, {'id': 2, 'name': 'bar'}, {'id': 1, 'name': 'gesiel'}]
d = defaultdict(list)
for x in data:
d[x['id']].append(x)
print(d)
# defaultdict(<class 'list'>, {1: [{'id': 1, 'name': 'foo'}, {'id': 1, 'name': 'gesiel'}], 2: [{'id': 2, 'name': 'bar'}]})
Upvotes: 3