Reputation: 23
Just having trouble with itertools.groupby. Given a list of dictionaries,
my_list = [
{'name': 'stock1', 'price': 200, 'shares': 100},
{'name': 'stock2', 'price': 1.2, 'shares': 1000},
{'name': 'stock3', 'price': 0.05, 'shares': 200000},
{'name': 'stock1', 'price': 200.2, 'shares': 50}]
From this list, I was hoping to create a dictionary, where the key is the name of the stock, and the value is a list of dictionaries of that stock, for example:
{'stock1': [{'name': 'stock1', 'price': 200, 'shares': 100}, {'name': 'stock1', 'price': 200.2, 'shares': 50}] }
I ran this code:
by_name = { name: list(items) for name, items in itertools.groupby(
my_list, key=lambda x: x['name'])}
, and this is the result I got:
{'stock1': [{'name': 'stock1', 'price': 200.2, 'shares': 50}],
'stock2': [{'name': 'stock2', 'price': 1.2, 'shares': 1000}],
'stock3': [{'name': 'stock3', 'price': 0.05, 'shares': 200000}]}
For stock1, I'm expecting 2 items in the list but it only has the latest entry from the original my_list. Can anyone please point out where the mistake is? Thank you!
Upvotes: 2
Views: 1577
Reputation: 147166
That isn't how itertools.groupby
works. From the manual:
It generates a break or new group every time the value of the key function changes (which is why it is usually necessary to have sorted the data using the same key function)
So to achieve the type of grouping you want, you need to sort my_list
first:
import itertools
my_list = [
{'name': 'stock1', 'price': 200, 'shares': 100},
{'name': 'stock2', 'price': 1.2, 'shares': 1000},
{'name': 'stock3', 'price': 0.05, 'shares': 200000},
{'name': 'stock1', 'price': 200.2, 'shares': 50}
]
my_list.sort(key=lambda x:x['name'])
by_name = { name: list(items) for name, items in itertools.groupby(
my_list, key=lambda x: x['name'])}
print(by_name)
Output
{'stock1': [{'name': 'stock1', 'price': 200, 'shares': 100},
{'name': 'stock1', 'price': 200.2, 'shares': 50}],
'stock2': [{'name': 'stock2', 'price': 1.2, 'shares': 1000}],
'stock3': [{'name': 'stock3', 'price': 0.05, 'shares': 200000}]
}
Upvotes: 4