Grouping Python dictionaries in hierarchical form - python

I have a list of dictionaries and I wanted to group the data. I used the following:
group_list = []
for key, items in itertools.groupby(res, operator.itemgetter('dept')):
group_list.append({key:list(items)})
For data that looks like this
[{'dept':1, 'age':10, 'name':'Sam'},
{'dept':1, 'age':12, 'name':'John'},
.
.
.
{'dept':2,'age':20, 'name':'Mary'},
{'dept':2,'age':11, 'name':'Mark'},
{'dept':2,'age':11, 'name':'Tom'}]
the output would be:
[{1:[{'dept':1, 'age':10, 'name':'Sam'},
{'dept':1, 'age':12, 'name':'John'}],
{2:[{'dept':2,'age':20, 'name':'Mary'},
{'dept':2,'age':11, 'name':'Mark'},
{'dept':2,'age':11, 'name':'Tom'}]
...
]
Now if I want to group using multiple keys say 'dept' and 'age', the above mentioned method returns
[{(2, 20): [{'age': 20, 'dept': 2, 'name': 'Mary'}]},
{(2, 11): [{'age': 11, 'dept': 2, 'name': 'Mark'},
{'age': 11, 'dept': 2, 'name': 'Tom'}]},
{(1, 10): [{'age': 10, 'dept': 1, 'name': 'Sam'}]},
{(1, 12): [{'age': 12, 'dept': 1, 'name': 'John'}]}]
The desired output would be:
[
{
2: {
20: [
{
'age': 20,
'dept': 2,
'name': 'Mary'
}
]
},
{
11: [
{
'age': 11,
'dept': 2,
'name': 'Mark'
},
{
'age': 11,
'dept': 2,
'name': 'Tom'
}
]
}
},
{
1: {
10: [
{
'age': 10,
'dept': 1,
'name': 'Sam'
}
]
},
{
12: [
{
'age': 12,
'dept': 1,
'name': 'John'
}
]
}
}
]
Can it be done with itertools? Or do I need to write that code myself?

Absolutely. You just need to apply itertools.groupby() for the second criterion first, then the other.

You would need to write a (probably recursive) bit of code to do this yourself - itertools doesn't have a tree-builder in it.

Thanks everyone for your help. Here is how I did it:
import itertools, operator
l = [{'dept':1, 'age':10, 'name':'Sam'},
{'dept':1, 'age':12, 'name':'John'},
{'dept':2,'age':20, 'name':'Mary'},
{'dept':2,'age':11, 'name':'Mark'},
{'dept':2,'age':11, 'name':'Tom'}]
groups = ['dept', 'age', 'name']
groups.reverse()
def hierachical_data(data, groups):
g = groups[-1]
g_list = []
for key, items in itertools.groupby(data, operator.itemgetter(g)):
g_list.append({key:list(items)})
groups = groups[0:-1]
if(len(groups) != 0):
for e in g_list:
for k,v in e.items():
e[k] = hierachical_data(v, groups)
return g_list
print hierachical_data(l, groups)

Related

sort dictionary alphabetically by key in odoo 13

I have built a dictionary to collect orders according to the client, the products that have been ordered and I need to order it alphabetically by client to use it in a qweb report, nothing I have tried so far has worked for me. Any ideas?
reparto_data = {
'Cliente 1': {
'Pastel manzana': 12,
'Bomba crema': 8,
},
'Cliente 2': {
'Cake calabaza': 18,
'Bombon chocolate': 8,
},
#...
}
reparto_data2 = {}
for i in sorted(reparto_data[key]):
reparto_data2[i] = reparto_data[i]
You need to sort the inner dictionaries.
So, iterate across the keys and values of the outer dict, and for each value (which is an inner dict), sort it.
from pprint import pprint
reparto_data = {
'Cliente 1': {
'Pastel manzana': 12,
'Bomba crema': 8,
},
'Cliente 2': {
'Cake calabaza': 18,
'Bombon chocolate': 8,
},
}
def sort_dict(d):
return {k: d[k] for k in sorted(d.keys())}
reparto_data2 = {k: sort_dict(v) for k,v in reparto_data.items()}
pprint(reparto_data2, width=1)
Output
{'Cliente 1': {'Bomba crema': 8,
'Pastel manzana': 12},
'Cliente 2': {'Bombon chocolate': 8,
'Cake calabaza': 18}}
You can try this too.
reparto_data = {
'Cliente 1': {
'Pastel manzana': 12,
'Bomba crema': 8,
},
'Cliente 2': {
'Cake calabaza': 18,
'Bombon chocolate': 8,
},
}
sorted_clients = sorted(reparto_data.keys(), key=lambda x:x.lower())
reparto_data2 = {i: reparto_data[i] for i in sorted_clients}
Output
{'Cliente 1': {'Pastel manzana': 12, 'Bomba crema': 8}, 'Cliente 2': {'Cake calabaza': 18, 'Bombon chocolate': 8}}
If want to use your own code just replace this with your loop
reparto_data2 = {i: reparto_data[i] for i in sorted(reparto_data[key])}
Thanks for your help but I have posed the question wrong since the dictionary contains objects.
The code that has worked for me is the following:
reparto_data2 = sorted(reparto_data.items(), key=lambda x: x[0].lower())

Create a new list by summing up existing list in Python

I have a list like this in Python:
my_list = [
{"id":1,"symbol":"ABC","quantity":100},
{"id":2,"symbol":"PQR","quantity":500},
{"id":3,"symbol":"ABC","quantity":300},
{"id":1,"symbol":"XYZ","quantity":320},
{"id":3,"symbol":"PQR","quantity":800},
]
I wanted to sum up a quantity which have similar symbols and create a new list. The new_list will look like this:
new_list = [
{ "symbol":"ABC","total_quantity":400,"ids":"1 3"}
{ "symbol":"PQR","total_quantity":1300,"ids":"2 3"}
{ "symbol":"XYZ","total_quantity":320,"ids":"1"}
]
I am fairly new to Python and tried some ways but not working. What can I try to achieve this?
A nice solution, is to use a defaultdict that facilitates the grouping per symbol, you just need a final step to build the ids
from collections import defaultdict
my_list = [{"id": 1, "symbol": "ABC", "quantity": 100},
{"id": 2, "symbol": "PQR", "quantity": 500},
{"id": 3, "symbol": "ABC", "quantity": 300},
{"id": 1, "symbol": "XYZ", "quantity": 320},
{"id": 3, "symbol": "PQR", "quantity": 800}, ]
expected = defaultdict(lambda: {'symbol': '', 'ids': [], "total_quantity": 0})
for row in my_list:
expected[row['symbol']]['symbol'] = row['symbol']
expected[row['symbol']]['ids'].append(str(row['id']))
expected[row['symbol']]['total_quantity'] += row['quantity']
result = [{**x, 'ids': " ".join(x['ids'])} for x in expected.values()]
if you are fine to use pandas, you can take this approach
import pandas as pd
df = pd.DataFrame.from_dict(my_list)
df1 = df.groupby('symbol').agg({'quantity':'sum',
'id':lambda x: ' '.join(map(str, x))}).reset_index()
Out:
{'0': {'symbol': 'ABC', 'quantity': 400, 'id': '1 3'},
'1': {'symbol': 'PQR', 'quantity': 1300, 'id': '2 3'},
'2': {'symbol': 'XYZ', 'quantity': 320, 'id': '1'}}
Something like this should work for you:
my_list = [
{"id":1,"symbol":"ABC","quantity":100},
{"id":2,"symbol":"PQR","quantity":500},
{"id":3,"symbol":"ABC","quantity":300},
{"id":1,"symbol":"XYZ","quantity":320},
{"id":3,"symbol":"PQR","quantity":800},
]
new_list = []
for item in my_list:
if item["symbol"] not in [new_item["symbol"] for new_item in new_list]:
new_list.append({"symbol":item["symbol"],"total_quantity":item["quantity"],"ids":str(item["id"])})
else:
for new_item in new_list:
if item["symbol"] == new_item["symbol"]:
new_item["total_quantity"] += item["quantity"]
new_item["ids"] += " "+str(item["id"])
break
print(new_list)
If you prefer a core Python solution, you can do:
my_list = [
{"id":1,"symbol":"ABC","quantity":100},
{"id":2,"symbol":"PQR","quantity":500},
{"id":3,"symbol":"ABC","quantity":300},
{"id":1,"symbol":"XYZ","quantity":320},
{"id":3,"symbol":"PQR","quantity":800},
]
res = []
for sym in sorted(set([x['symbol'] for x in my_list])):
tmp = {}
tmp['symbol'] = sym
tmp['ids'] = r' '.join([str(x['id']) for x in my_list if x['symbol'] == sym])
tmp['total_quantity'] = sum([x['quantity'] for x in my_list if x['symbol'] == sym])
res.append(tmp)
print(res)
#[{'symbol': 'ABC', 'total_quantity': 400, 'ids': '1 3'},
# {'symbol': 'PQR', 'total_quantity': 1300, 'ids': '2 3'},
# {'symbol': 'XYZ', 'total_quantity': 320, 'ids': '1'}]

Need help in extracting key list from List of dictionaries and corresponding counts using Python

Hi I am looking to extract list of all keys from a List of dictionaries and their corresponding counts using Python. Used below code but counden't do it can some one help me in this regard
The Data looks like this,
people = [{'name': "Tom", 'age': 10, "city" : "NewYork"},
{'name': "Mark", 'age': 5, "country" : "Japan"},
{'name': "Pam", 'age': 7, "city" : "London"},
{'name': "Tom", 'hight': 163, "city" : "California"},
{'name': "Lena", 'weight': 45, "country" : "Italy"},
{'name': "Ben", 'age': 17, "city" : "Colombo"},
{'name': "Lena", 'gender': "Female", "country" : "Italy"},
{'name': "Ben", 'gender': "Male", "city" : "Colombo"}]
def search(name):
p_count = 0
for p in people:
if p['name'] == name:
p_count = p_count+1
return p, p_count
search("Pam")
def search1(list_dict):
for i in list_dict:
def getList(i):
return i.keys()
search1(people)
I want out put like the following,
name: 8, age: 4, City:3, Country: 2 etc..
I am new to this can some one help me in this
Just create a temporary dictionary to hold the count result, and for each key in each dictionary of the list, increase the the count by 1 using dict.get with default value as 0, finally return this dictionary.
def getKeyCount(lst):
out = {}
for d in lst:
for k in d.keys():
out[k] = out.get(k, 0) + 1
return out
getKeyCount(people)
#output
{'name': 8, 'age': 4, 'city': 5, 'country': 3, 'hight': 1, 'weight': 1, 'gender': 2}
You can make a hash table, and iterate over the keys of each
hash = {}
for d in list_dict:
for k in d.keys():
if k not in hash:
hash[k] = 0
hash[k] += 1
print(hash)

Merge two dictionaries with an identical key using foor loop

i have these two dictionaries and i would like to add the data dict1 in dict2. how can i do that with python ?
dict1 = {
213688169:
{'stationCode': '6003',
'station_id': 213688169,
'num_bikes_available': 10,
'numBikesAvailable': 10,
'num_bikes_available_types': [{'mechanical': 10}, {'ebike': 0}],
'num_docks_available': 10,
'numDocksAvailable': 10,
'is_installed': 1,
'is_returning': 1,
'is_renting': 1,
'last_reported': 1619207955}
}
dict2 = {
213688169:
{'station_id': 213688169,
'name': 'Benjamin Godard - Victor Hugo',
'lat': 48.865983,
'lon': 2.275725,
'capacity': 35,
'stationCode': '16107'}
}
i tried this but it's too long and complicated :
donnees=[]
for i in stations:
for j in velib_description :
if i['station_id'] == j['station_id']:
List={}
List['name'] = i['name']
List['lat'] = i['lat']
List['lon'] = i['lon']
List['capacity'] = i['capacity']
List['num_bikes_available'] = j['num_bikes_available']
List['num_bikes_available_types'] = j['num_bikes_available_types']
List['last_reported'] = j['last_reported']
donnees.append(List)
I want to add in dict_2 = {num_bikes_available', 'num_bikes_available_types', last_reported': 1619207955 }
thank you
Perhaps you want dict.update?
dict1 = {
213688169: {
"stationCode": "6003",
"station_id": 213688169,
"num_bikes_available": 10,
"numBikesAvailable": 10,
"num_bikes_available_types": [{"mechanical": 10}, {"ebike": 0}],
"num_docks_available": 10,
"numDocksAvailable": 10,
"is_installed": 1,
"is_returning": 1,
"is_renting": 1,
"last_reported": 1619207955,
}
}
dict2 = {
213688169: {
"station_id": 213688169,
"name": "Benjamin Godard - Victor Hugo",
"lat": 48.865983,
"lon": 2.275725,
"capacity": 35,
"stationCode": "16107",
}
}
dict1_item = dict1[213688169]
dict2[213688169].update({k: v for k, v in dict1_item.items() if k not in dict2})
dict2
This prints
{213688169: {'station_id': 213688169,
'name': 'Benjamin Godard - Victor Hugo',
'lat': 48.865983,
'lon': 2.275725,
'capacity': 35,
'stationCode': '6003',
'num_bikes_available': 10,
'numBikesAvailable': 10,
'num_bikes_available_types': [{'mechanical': 10}, {'ebike': 0}],
'num_docks_available': 10,
'numDocksAvailable': 10,
'is_installed': 1,
'is_returning': 1,
'is_renting': 1,
'last_reported': 1619207955}}
We're using a comprehension to get all the key/values from the first dictionary that aren't in the second, then updating the second dictionary. We have to do a little munging with the 213688169 key because your dictionary is nested.
You can use a dictionary comprehension with a dictionary merge trick:
dict3 = {k: {**v, **dict2[k]} for k, v in dict1.items()}
or for Python 3.9 and later:
dict3 = {k: v | dict2[k] for k, v in dict1.items()}

Python defaultdict get original dictionary

Let's say we have:
from collections import defaultdict
original_dict = { 'somegroupofelements':{'name':1, 'group':1 ,'results':[1,2,3,4]}, 'somegroupofelements2':{'name':2, 'group': 2 ,'results':[1,2,3,4]}, 'somegroupofelements3':{'name':3, 'group':3 ,'results':[1,2,3,4]} }
new_dict = defaultdict(list)
for key, value in original_dict.iteritems():
# i need to organize things grouped for making the right latex tables
# and for updating some values...
value['key']=key
new_dict[value['group']].append(value)
I want that new_dict, after I've done my work, to be organized again just like the original_dict? Like reconstruct the original_dict from the new_dict.
So you end up with a dictionary in the form:
>>> d = { 100 : [{'name':1, 'group':100, 'key':'group1'},
... {'name':2, 'group':100, 'key':'group2'}],
... 200 : [{'name':3, 'group':200, 'key':'group3'}] }
Which can be transformed back into a dictionary using a dict comprehension:
>>> orig = { x['key']:x for v in d.values() for x in v }
>>> orig
{'group1': {'group': 100, 'name': 1, 'key': 'group1'},
'group3': {'group': 200, 'name': 3, 'key': 'group3'},
'group2': {'group': 100, 'name': 2, 'key': 'group2'}}
If you want, you can then delete the superflous key field of the items:
>>> for v in orig.values(): del v['key']
...
>>> orig
{'group1': {'group': 100, 'name': 1},
'group3': {'group': 200, 'name': 3},
'group2': {'group': 100, 'name': 2}}

Categories

Resources