How can I apply groupby on django queryset - python

I have a queryset say,
a_query = <QuerySet [{'id': 1, 'user_id': 10, 'name': 'xyz'}, {'id': 2, 'user_id': 10, 'name': 'abc'},{'id': 3, 'user_id': 12, 'name': 'pqr'}]>
So here I want to apply groupby on user_id so the result should be,
[(10, [['xyz', 1], ['abc', 2]]), (12, ['pqr', 1])]
I tried using itemgetter and groupby but that doesn't work.

Related

Extract values from array in python

I'm having some trouble accessing a value that is inside an array that contains a dictionary and another array.
It looks like this:
[{'name': 'Alex',
'number_of_toys': [{'classification': 3, 'count': 383},
{'classification': 1, 'count': 29},
{'classification': 0, 'count': 61}],
'total_toys': 473},
{'name': 'John',
'number_of_toys': [{'classification': 3, 'count': 8461},
{'classification': 0, 'count': 3825},
{'classification': 1, 'count': 1319}],
'total_toys': 13605}]
I want to access the 'count' number for each 'classification'. For example, for 'name' Alex, if 'classification' is 3, then the code returns the 'count' of 383, and so on for the other classifications and names.
Thanks for your help!
Not sure what your question asks, but if it's just a mapping exercise this will get you on the right track.
def get_toys(personDict):
person_toys = personDict.get('number_of_toys')
return [ (toys.get('classification'), toys.get('count')) for toys in person_toys]
def get_person_toys(database):
return [(personDict.get('name'), get_toys(personDict)) for personDict in database]
This result is:
[('Alex', [(3, 383), (1, 29), (0, 61)]), ('John', [(3, 8461), (0, 3825), (1, 1319)])]
This isn't as elegant as the previous answer because it doesn't iterate over the values, but if you want to select specific elements, this is one way to do that:
data = [{'name': 'Alex',
'number_of_toys': [{'classification': 3, 'count': 383},
{'classification': 1, 'count': 29},
{'classification': 0, 'count': 61}],
'total_toys': 473},
{'name': 'John',
'number_of_toys': [{'classification': 3, 'count': 8461},
{'classification': 0, 'count': 3825},
{'classification': 1, 'count': 1319}],
'total_toys': 13605}]
import pandas as pd
df = pd.DataFrame(data)
print(df.loc[0]['name'])
print(df.loc[0][1][0]['classification'])
print(df.loc[0][1][0]['count'])
which gives:
Alex
3
383

from list of dicts to list of lists of dicts with same values

I have list of dicts:
dict_list = [{'Id': 0, 'UserID': 1, 'Name': 'John'},
{'Id': 1, 'UserID': 2, 'Name': 'Martin'},
{'Id': 2, 'UserID': 1, 'Name': 'Rob'},
{'Id': 3, 'UserID': 1, 'Name': 'Neil'},
{'Id': 4, 'UserID': 2, 'Name': 'Bill'}]
How to make a list of lists of dicts that grouped by key UserID?
So I want to group dicts with the same value of key UserID to lists.
I expect smth like that:
[[{'Id': 0,'UserID': 1, 'Name': 'John'},
{'Id': 2,'UserID': 1, 'Name': 'Rob'},
{'Id': 3,'UserID': 1, 'Name': 'Neil'}],
[{'Id': 1,'UserID': 2, 'Name': 'Martin'},
{'Id': 4,'UserID': 2, 'Name': 'Bill'}]]
First sort the dict_list based on UserID and then use itertools.groupby to group the results based on UserID
>>> from itertools import groupby
>>> key = lambda d: d['UserID']
>>> res = [list(grp) for _,grp in groupby(sorted(dict_list, key=key), key)]
>>>
>>> pprint(res)
[[{'Id': 0, 'Name': 'John', 'UserID': 1},
{'Id': 2, 'Name': 'Rob', 'UserID': 1},
{'Id': 3, 'Name': 'Neil', 'UserID': 1}],
[{'Id': 1, 'Name': 'Martin', 'UserID': 2},
{'Id': 4, 'Name': 'Bill', 'UserID': 2}]]
It's also possible to use list comprehension like this:
dict_list = [{'Id': 0, 'UserID': 1, 'Name': 'John'},
{'Id': 1, 'UserID': 2, 'Name': 'Martin'},
{'Id': 2, 'UserID': 1, 'Name': 'Rob'},
{'Id': 3, 'UserID': 1, 'Name': 'Neil'},
{'Id': 4, 'UserID': 2, 'Name': 'Bill'}]
user_ids=set([x['UserID'] for x in dict_list])
result_list=[]
for user_id in user_ids:
user_id_list = [x for x in dict_list if x['UserID']==user_id]
result_list.append(user_id_list)
print(result_list)
from itertools import groupby
dict_list = [{'Id': 0, 'UserID': 1, 'Name': 'John'},
{'Id': 1, 'UserID': 2, 'Name': 'Martin'},
{'Id': 2, 'UserID': 1, 'Name': 'Rob'},
{'Id': 3, 'UserID': 1, 'Name': 'Neil'},
{'Id': 4, 'UserID': 2, 'Name': 'Bill'}]
res =[list(group) for _,group in groupby(sorted(dict_list, key=lambda f: f['UserID']), lambda f: f['UserID'])]
print(res)

Sorting a list of dictionary based on the length of one of the values of the dictionary

I have a list of dictionaries. The dictionaries have a key called friends whose value is a list of ids. I want to sort the list of dictionary on the basis of number of ids in the friends list.
users=[{'id': 0, 'name': 'Hero', 'friends': [1, 2]},
{'id': 1, 'name': 'Dunn', 'friends': [0, 2, 3]},
{'id': 2, 'name': 'Sue', 'friends': [0, 1, 3]},
{'id': 3, 'name': 'Chi', 'friends': [1, 2, 4]},
{'id': 4, 'name': 'Thor', 'friends': [3, 5]},
{'id': 5, 'name': 'Clive', 'friends': [4, 6, 7]},
{'id': 6, 'name': 'Hicks', 'friends': [5, 8]},
{'id': 7, 'name': 'Devin', 'friends': [5, 8]},
{'id': 8, 'name': 'Kate', 'friends': [6, 7, 9]},
{'id': 9, 'name': 'Klein', 'friends': [8]}]
How do i proceed with it?
I believe this is what you meant:
sorted(users, key=lambda d: len(d['friends']))
The list of users is sorted depending on the number of friends. Users with less friends appear first. If two users have the same number of friends, the order in which they appear is random.

Merge dicts from a list of dicts based on some key/value pair

I have a list of dicts shown below , I want to merge some dicts into one based some key/value pair.
[
{'key': 16, 'value': 3, 'user': 3, 'id': 7},
{'key': 17, 'value': 4, 'user': 3, 'id': 7},
{'key': 17, 'value': 5, 'user': 578, 'id': 7},
{'key': 52, 'value': 1, 'user': 3, 'id': 48},
{'key': 46, 'value': 2, 'user': 578, 'id': 48}
]
Now as you can see dict 1 & 2 have same values for user & id keys. So it is possible to merge these two dicts like
[
{'key': [16,17], 'value': [3,4], 'user': 3, 'id': 7},
{'key': [17], 'value': [5], 'user': 578, 'id': 7},
{'key': [52], 'value': [1], 'user': 3, 'id': 48},
{'key': [46], 'value': [2], 'user': 578, 'id': 48}
]
means user & id value must be unique together.What will be the efficient way to merge (if possible)
Following function will convert the list of dictionaries to new format:
def convert(d):
res = {}
for x in d:
key = (x['user'], x['id'])
if key in res:
res[key]['key'].append(x['key'])
res[key]['value'].append(x['value'])
else:
x['key'] = [x['key']]
x['value'] = [x['value']]
res[key] = x
return res.values()
It will mutate the original dictionaries and the ordering of dictionaries in the result will be random. When applied to the input it will produce following result:
[
{'id': 7, 'value': [5], 'key': [17], 'user': 578},
{'id': 7, 'value': [3, 4], 'key': [16, 17], 'user': 3},
{'id': 48, 'value': [1], 'key': [52], 'user': 3},
{'id': 48, 'value': [2], 'key': [46], 'user': 578}
]
Let dicts be your original list of dictionaries. This idea maps unique combinations of user and id to defaultdict(list) objects. The final result will be the list of values from that dictionary.
from collections import defaultdict
tmp = defaultdict(dict)
for info in dicts:
tmp[(info['user'], info['id'])].setdefault('key', []).append(info['key'])
tmp[(info['user'], info['id'])].setdefault('value', []).append(info['value'])
for (user, id_), d in tmp.items(): # python2: use iteritems
d.update(dict(user=user, id=id_))
result = list(tmp.values()) # python2: tmp.values() already gives a list
del tmp
You can use following aggregate function:
def aggregate(lst):
new = {}
for d in lst:
new.setdefault((d['user'], d['id']), []).append(d)
for k, d in new.items():
if len(d) > 1:
keys, values = zip(*[(sub['key'], sub['value']) for sub in d])
user, id_ = k
yield {'key': keys, 'value': values, 'user': user, 'id': id_}
else:
yield d[0]
print list(aggregate(lst))
[{'id': 7, 'value': 5, 'key': 17, 'user': 578},
{'id': 7, 'value': (3, 4), 'key': (16, 17), 'user': 3},
{'id': 48, 'value': 1, 'key': 52, 'user': 3},
{'id': 48, 'value': 2, 'key': 46, 'user': 578}]

mongodb elemMatch in dual array

I have a problem try to use $elemMatch in dual nested array:
Suppose I have this a document:
a = {'cart': [[{'id': 1, 'count': 1}, {'id': 2, 'count': 3}], [{'id': 1, 'count': 5}]]}
And I want to select a document out when id is 1 and count greater than 2:
db.cart.find_one({'cart.0.id': 1, 'cart.0.count': {'$gt': 2}})
But this query will select a out.
Then I have tried these queries:
db.cart.find_one({'cart': {'$elemMatch': {'id': 1, 'count': {'$gt': 2}}}})
db.cart.find_one({'cart': {'$elemMatch': {'id': 2, 'count': {'$gt': 2}}}})
db.cart.find_one({'cart.0': {'$elemMatch': {'id': 1, 'count': {'$gt': 2}}}})
db.cart.find_one({'cart.0': {'$elemMatch': {'id': 2, 'count': {'$gt': 2}}}})
But all return None.
So do $elemMatch support the nested array match? If so, how shall I tune my query?
Given the fact that you have an array within an array, I think you could try something like
db.cart.find_one({'cart': {'$elemMatch': { '$elemMatch' : {'id': 1, 'count': {'$gt': 2}}}}})

Categories

Resources