data = [
{
'name': 'Jack',
'points': 10
},
{
'name': 'John',
'points': 12
},
{
'name': 'Jack',
'points': 15
},
{
'name': 'Harry',
'points': 11
}
]
Output:
Jack: 25 points ,
John: 12 points ,
Harry: 11 points
Is there anyway to achieve this without using for loop ?
I can achieve this by storing key value pair or name and points and adding the points if already exists in the dictionary. But is there any alternative way to achieve this ?
You can use groupby from itertools:
from itertools import groupby
key = lambda d: d['name']
result = {n: sum(v['points'] for v in vs) for n, vs in groupby(sorted(data, key=key), key)}
Result:
{'Harry': 11, 'Jack': 25, 'John': 12}
Related
I have a list of dictionaries called dictList that has data like so:
[{'id': '5', 'total': '39'}, {'id': '5', 'total': '43'}].
I am trying to create a new dictionary that uses the id as the key and total as the value.
So have tried this:
keys = [d['id'] for d in dictList]
values = [d['total'] for d in dictList]
new_dict[str(keys)]= values
However the output is: {"['5', '5']": [39, 43]}
I am not sure what is going on, I am just trying to get the id and the respective total like 5, 39 and 5, 43 in to new_dict.
EDIT:
Please note that dictList contains all the products with ID 5. There are other fields, but I didn't include them.
One approach:
data = [{'id': '5', 'total': '39'}, {'id': '5', 'total': '43'}]
res = {}
for d in data:
key = d["id"]
if key not in res:
res[key] = 0
res[key] += int(d["total"])
print(res)
Output
{'5': 82}
Alternative using collections.defaultdict:
from collections import defaultdict
data = [{'id': '5', 'total': '39'}, {'id': '5', 'total': '43'}]
res = defaultdict(int)
for d in data:
key = d["id"]
res[key] += int(d["total"])
print(res)
Output
defaultdict(<class 'int'>, {'5': 82})
Use sorted and itertools.groupby to group by the 'id' key of each list element:
import itertools
dictList = [{'id': '5', 'total': '39'}, {'id': '10', 'total': '10'},
{'id': '5', 'total': '43'}, {'id': '10', 'total': '22'}]
groups = itertools.groupby(sorted(dictList, key=lambda item: item['id'])
, key=lambda item: item['id'])
Next, take the sum of each group:
product_totals = {
key: sum(int(item['total']) for item in grp)
for key, grp in groups
}
Which gives:
{'10': 32, '5': 82}
If you have lots of such entries, you could consider using pandas to create a dataframe. Pandas has vectorized methods that help you crunch numbers faster. The idea behind finding the sum of totals is the same, except in this case we don't need to sort because pandas.groupby takes care of that for us
>>> import pandas as pd
>>> df = pd.DataFrame(dictList)
>>> df['total'] = df['total'].astype(int)
>>> df
id total
0 5 39
1 10 10
2 5 43
3 10 22
>>> df.groupby('id').total.sum()
id
10 32
5 82
Name: total, dtype: int32
>>> df.groupby('id').total.sum().as_dict()
{'10': 32, '5': 82}
Although I'm not sure what you are trying to do, try this:
for d in dictlist:
if new_dict[d["id"]]:
new_dict[d["id"]] += d["total"]
else:
new_dict[d["id"]] = d["total"]
At a high-level, how does pandas do sorting? For example, if I had the following dataframe:
l = [{
'Name': 'Todd',
'Age': 20,
}, {
'Name': 'Sarah',
'Age': 25,
}, {
'Name': 'Sarah',
'Age': 29,
}]
df = pd.DataFrame(l)
df.sort_values(by=['Name', 'Age'])
Is this using a python built-in, such as:
sorted(l, key = lambda x: (x['Name'], x['Age']))
Or is the pandas sort something more complex? What is its basic implementation?
I have three list, I want to convert into a specific dict
A = ["a", "b"]
B = ["10", "20"]
C = ["key1", "key2"]
I want a dict like that
"key1": {
"name": "a",
"age": 10
},
"key2": {
"name": "b",
"age": 20
}
I try different way by different step, but I don't get this dict
for key in A:
dict_A["name"].append(key)
Using a dictionary comprehension:
res = {key: {'name': name, 'age': age} for key, name, age in zip(C, A, B)}
This gives:
{'key1': {'age': '10', 'name': 'a'}, 'key2': {'age': '20', 'name': 'b'}}
zip allows you to aggregate elements from each iterable by index.
If you don't want to use zip then you can use enumerate as given below:
print ({v:{"name": A[k],"age": B[k]} for k, v in enumerate(C)})
In[1]: {c: {'name': a, 'age': b} for a, b, c in zip(A, B, C)}
Out[1]: {'key1': {'name': 'a', 'age': '10'}, 'key2': {'name': 'b', 'age': '20'}}
How about
for a,b,c in zip(A, B, C):
your_dict[c] = {"name" : a, "age": b}
Following is the list of dictionary,
[{'12': 'carrom', 'name': 'tom'},
{'7': 'tennis', 'name': 'tom'},
{'5': 'cycling', 'name': 'tom'},
{'9': 'tennis', 'name': 'sam'}]
How to build a list comprehension in the below format?
{'tom' : [12,7,5], 'sam' : [9]}
With the understanding that there are only two keys per dictionary, you will need to loop through each dictionary and append to a defaultdict:
from collections import defaultdict
d = defaultdict(list)
for l in lst:
# Pop the name key, so we're only left with the other key.
name_key = l.pop('name')
# Extract the remaining key from `l`.
other_key = list(l)[0]
d[name_key].append(other_key)
print(d)
# defaultdict(list, {'sam': ['9'], 'tom': ['12', '7', '5']})
Note that this iterates destructively over your dictionaries. To get d as a plain-dict, use
d = dict(d)
Since defaultdict is a subclass of dict.
Another option is pandas (since you have the library):
df = pd.DataFrame(lst).set_index('name')
df
12 5 7 9
name
tom carrom NaN NaN NaN
tom NaN NaN tennis NaN
tom NaN cycling NaN NaN
sam NaN NaN NaN tennis
df.notna().dot(df.columns).groupby(level=0).agg(list).to_dict()
# {'sam': ['9'], 'tom': ['12', '7', '5']}
You can use itertools.groupby to group your list of dictionaries first,
from itertools import groupby
groupby_list = [list(g) for k, g in groupby(alist, key=lambda x: x['name'])]
That will output a list,
[[{'12': 'carrom', 'name': 'tom'},
{'7': 'tennis', 'name': 'tom'},
{'5': 'cycling', 'name': 'tom'}],
[{'9': 'tennis', 'name': 'sam'}]]
Then you have to get keys of each nested list, and filter the string key by using isdigit() method. I combine it in a long comprehension expression which is a little complicated.
[{group[0]['name'] : [int(number) for number in list(set().union(*(d.keys() for d in list(group)))) if number.isdigit()]} for group in groupby_list]
The result is what you want:
[{'tom': [12, 7, 5]}, {'sam': [9]}]
Hope this answer will be helpful.
Cheers.
your_list_name = [i['name'] for i in your_list]
your_list_name
['tom', 'tom', 'tom', 'sam']
your_list_keys = [i.keys() for i in your_list]
your_list_digit_keys = [[item for item in sublist if item.isdigit()==True] for sublist in your_list_keys]
your_list_digit_keys = [item for sublist in your_list_digit_keys for item in sublist]
your_list_digit_keys = list(map(int, your_list_digit_keys))
your_list_digit_keys
[12, 7, 5, 9]
my_dict={} # Initializing the dictionary
for i in range(len(your_list_name)):
key = your_list_name[i]
if key in my_dict:
my_dict[key] += [your_list_digit_keys[i]]
else:
my_dict[key] = [your_list_digit_keys[i]]
my_dict
{'sam': [9], 'tom': [12, 7, 5]}
I have a list like this:
li = [
{
'name': 'Lee',
'age': 22
},
{
'name': 'Mike',
'age': 34
},
{
'name': 'John',
'age': 23
}
]
I want sort the list with sorted method, and sort by the the age key
How to achieve it?
Use a key function:
li_sorted = sorted(li, key=lambda x: x['age'])
The Python3 equivalent of what #kojiro suggests is this
>>> sorted(li, key=lambda x:sorted(x.items()))
[{'age': 22, 'name': 'Lee'}, {'age': 23, 'name': 'John'}, {'age': 34, 'name': 'Mike'}]
Clearly this is less efficient than
>>> sorted(li, key=lambda x:x['age'])
[{'age': 22, 'name': 'Lee'}, {'age': 23, 'name': 'John'}, {'age': 34, 'name': 'Mike'}]
anyway. There is also the advantage that it doesn't rely on the fact that 'age' < 'name'
Here's how to write the same thing using itemgetter
>>> from operator import itemgetter
>>> sorted(li, key=itemgetter('age'))
[{'age': 22, 'name': 'Lee'}, {'age': 23, 'name': 'John'}, {'age': 34, 'name': 'Mike'}]