I have a dictionary below
Fist i need to check a parent which contain Main or Contract.
FOr Main add name to the level1 dictionary and Contract level2 dictionary
d = {"employee": [
{
"id": "18",
"name": "Manager",
"parent": "Main level"
},
{
"id": "19",
"name": "Employee",
"parent": "Main level"
},
{
"id": "32",
"name": "Contract",
"parent": "Contract level"
},
{
"id": "21",
"name": "Admin",
"parent": "Main level"
},
]}
Expected out is below
{"employee": [
{'level1':['Manager','Employee']},
{'level2':['Test','HR']},
{
"id": "18",
"name": "Manager",
"parent": "Main level"
},
{
"id": "19",
"name": "Employee",
"parent": "Main level"
},
{
"id": "32",
"name": "Test",
"parent": "Contract level"
},
{
"id": "21",
"name": "HR",
"parent": "Contract level"
},
]}
Code
d['level1'] = {}
d['level2'] = {}
for i,j in d.items():
#check parent is Main
if j['parent'] in 'Main':
d['level1'] = j['name']
if j['parent'] in 'Contract':
d['level2'] = j['name']
I got the error TypeError: list indices must be integers or slices, not str
Your for loop is misguided.
You made 3 mistakes:
You tried looping over the parent dict instead of the actual list of employees.
You are using x in y backwards, for checking if one string contains another.
You are not actually appending new names to the "levels" lists.
Try this:
d["level1"] = []
d["level2"] = []
for j in d["employee"]:
# check parent is Main
if "Main" in j["parent"]:
d["level1"] += [j["name"]]
if "Contract" in j["parent"]:
d["level2"] += [j["name"]]
That will give you the "levels" as dict "siblings" of the employees (instead of in the list of employees, which is what you actually want).
To get the exact result you want, you would have to do something like this:
level1 = []
level2 = []
for j in d["employee"]:
# check parent is Main
if "Main" in j["parent"]:
level1 += [j["name"]]
if "Contract" in j["parent"]:
level2 += [j["name"]]
d["employee"] = [{"level1": level1}, {"level2": level2}] + d["employee"]
Try this:
dd = {'Main level': 'level1', 'Contract level': 'level2'}
res = {}
for x in d['employee']:
k = dd[x['parent']]
if k in res:
res[k].append(x['name'])
else:
res[k] = [x['name']]
d['employee'] = [{k: v} for k, v in res.items()] + d['employee']
print(d)
Output:
{'employee': [{'level1': ['Manager', 'Employee', 'Admin']},
{'level2': ['Contract']},
{'id': '18', 'name': 'Manager', 'parent': 'Main level'},
{'id': '19', 'name': 'Employee', 'parent': 'Main level'},
{'id': '32', 'name': 'Contract', 'parent': 'Contract level'},
{'id': '21', 'name': 'Admin', 'parent': 'Main level'}]}
Related
dict_example = {
"abc": [
{
"name": "bcd",
"gender": "male",
"options": {
"emp_id": "a10734",
"address": "cfg",
"dept": "IT",
},
}
]
}
I have above dictionary and I need to add below values to options programmatically.
"desgn":"Engineer",
"project" : "xyz",
I need output in the below formart
dict_example = {
"abc": [
{
"name": "bcd",
"gender": "male",
"options": {
"emp_id": "a10734",
"address": "cfg",
"dept": "IT",
"desgn":"Engineer",
"project" : "xyz",
},
}
]
}
Can anyone help me with the above problem it will be great!
You can simply use the keys and indices to reach the item and add or change it:
dict_example['abc'][0]['options']['design'] = 'Engineer'
dict_example['abc'][0]['options']['project'] = 'xyz'
print(dict_example)
The output will be:
{'abc': [{'name': 'bcd', 'gender': 'male', 'options': {'emp_id': 'a10734', 'address': 'cfg', 'dept': 'IT', 'design': 'Engineer', 'project': 'xyz'}}]}
for an input json
[{
"Name": "John",
"Age": "23",
"Des": "SE"
},
{
"Name": "Rai",
"Age": "33",
"Des": "SSE"
},
{
"Name": "James",
"Age": "42",
"Des": "SE"
}
]
I want to filter out the json data where only "Des":"SE" is true
required output
[{
"Name": "John",
"Age": "23"
},
{
"Name": "James",
"Age": "42"
}
]
A list comprehension should do it:
out = [{'Name':d['Name'], 'Age':d['Age']} for d in lst if d['Des']=='SE']
Another way:
out = [d for d in lst if d.pop('Des')=='SE']
Output:
[{'Name': 'John', 'Age': '23'}, {'Name': 'James', 'Age': '42'}]
To make it more dynamic if each json has more elements:
import json
input_str = '[{"Name": "John", "Age": "23", "Des": "SE"}, {"Name": "Rai", "Age": "33", "Des": "SSE"}, {"Name": "James", "Age": "42", "Des": "SE"}]'
input_list = json.loads(input_str)
# If you already converted to a list of dicts, then you don't need the above
# Using pop here removes the key you are using to filter
output = [each for each in input_list if each.pop("Des") == "SE"]
using the json module, you can load a file using loads or a string using load. From there, it acts as a normal python list of dictionaries which you can iterate over and check the keys of. From there, you simply create a new list of dictionaries that match your desired pattern and remove the key you are no longer using. Example:
import json
jsonString = """[{
"Name": "John",
"Age": "23",
"Des": "SE"
},
{
"Name": "Rai",
"Age": "33",
"Des": "SSE"
},
{
"Name": "James",
"Age": "42",
"Des": "SE"
}
]"""
jsonList = json.loads(jsonString)
filteredList = []
def CheckDes(dataDict: dict):
if dataDict['Des'] == 'SE':
dataDict.pop('Des')
filteredList.append(dataDict)
print(jsonList)
"""
[
{
'Name': 'John',
'Age': '23',
'Des': 'SE'
},
{
'Name': 'Rai',
'Age': '33',
'Des': 'SSE'
},
{
'Name': 'James',
'Age': '42',
'Des': 'SE'
}
]"""
[CheckDes(dataDict) for dataDict in jsonList]
print(filteredList)
"""[
{
'Name': 'John',
'Age': '23'
},
{
'Name': 'James',
'Age': '42'
}
]
"""
list is below
preference dictionary is below
if all the keys and values except type will be same then ..
Need to compare type in each list which is highest order in preference dictionary
Output is list of dictionary which type is highest order
list_ = [
{
"id": "11",
"name": "son",
"email": "n#network.com",
"type": "Owner"
},
{
"id": "11",
"name": "son",
"email": "n#network.com",
"type": "Manager"
},
{
"id": "21",
"name": "abc",
"email": "abc#network.com",
"type": "Employ"
},
{
"id": "21",
"name": "abc",
"email": "abc#network.com",
"type": "Manager"
}
]
A preference dictionary = {'Owner': 1, 'Manager':2, 'employ':3, 'HR': 4 }
My expected output dictionary below
[{'id': '11', 'name': 'son', 'email': 'n#network.com', 'type': 'Owner'},
{'id':'21','name': 'abc','email': 'abc#network.com','type': 'Manager'}]
new_list = []
for each in list_:
if each['type'] in priority.keys():
if each['id'] not in new_list:
new_list.append(each)
You can simply do src.sort(key = lambda x : preference[x["type"]]) and your list will be sorted.
This solution groups all the elements by id, and sorts the groups according to the preference (so that the Owner is first and HR is last) and then just picks the first from each group:
from collections import defaultdict
src = [
{
"id": "11",
"name": "son",
"email": "n#network.com",
"type": "Owner"
},
{
"id": "11",
"name": "son",
"email": "n#network.com",
"type": "Manager"
},
{
"id": "21",
"name": "abc",
"email": "abc#network.com",
"type": "Employ"
},
{
"id": "21",
"name": "abc",
"email": "abc#network.com",
"type": "Manager"
}
]
preference = {'Owner': 1, 'Manager':2, 'Employ':3, 'HR': 4 }
d = defaultdict(list)
# group all the records by id
for item in src:
d[item['id']].append(item)
# sort each group by the preference
for item in d.values():
item.sort(key=lambda x: preference[x['type']])
# select only the first from each group
result = [item[0] for item in d.values()]
print(result)
Output:
[{'id': '11', 'name': 'son', 'email': 'n#network.com', 'type': 'Owner'}, {'id': '21', 'name': 'abc', 'email': 'abc#network.com', 'type': 'Manager'}]
You could create a priority queue:
from queue import PriorityQueue
priority = {'Owner': 1, 'Manager':2, 'employ':3, 'HR': 4 }
q = PriorityQueue()
for elem in list_:
p = priority[elem['type']]
q.put((p, id(elem), elem))
Or you could also sort a list based on the type with:
priority_list = sorted(list_, key=lambda x: priority[x['type']], reverse=True)
Well here's my shot!
It isn't beautiful but it seems to work.
list_ = [
{
"id": "11",
"name": "son",
"email": "n#network.com",
"type": "Owner"
},
{
"id": "11",
"name": "son",
"email": "n#network.com",
"type": "Manager"
},
{
"id": "21",
"name": "abc",
"email": "abc#network.com",
"type": "Employ"
},
{
"id": "21",
"name": "abc",
"email": "abc#network.com",
"type": "Manager"
}
]
new = dict( Owner = 0, Manager = 0, Employ = 0, HR = 0 )
for a in list_ :
type_ = a[ 'type' ]
if type_ == 'Owner':
new[ 'Owner' ] += 1
if type_ == 'Manager':
new[ 'Manager' ] += 1
if type_ in [ 'Employ', 'Manager' ]:
new[ 'Employ' ] += 1
new[ 'HR' ] += 1
print( new )
I have a dataframe like below, where each 'level' drills down into more detail, with the last level having an id value.
data = [
{'id': 1, 'level_1': 'Animals', 'level_2': 'Carnivores', 'level_3': 'Felidae', 'level_4', 'Siamese Cat'},
{'id': 2, 'level_1': 'Animals', 'level_2': 'Carnivores', 'level_3': 'Felidae', 'level_4', 'Javanese Cat'},
{'id': 3, 'level_1': 'Animals', 'level_2': 'Carnivores', 'level_3': 'Ursidae', 'level_4', 'Polar Bear'},
{'id': 4, 'level_1': 'Animals', 'level_2': 'Carnivores', 'level_3': 'Canidae', 'level_4', 'Labradore Retriever'},
{'id': 5, 'level_1': 'Animals', 'level_2': 'Carnivores', 'level_3': 'Canidae', 'level_4', 'Golden Retriever'}
]
I want to turn this into a nested dictionary of parent / child relationships like below.
var data = {
"name": "Animals",
"children": [
{
"name": "Carnivores",
"children": [
{
"name": "Felidae",
"children": [
{
"id": 1,
"name": "Siamese Cat",
"children": []
},
{
"id": 2,
"name": "Javanese Cat",
"children": []
}
]
},
{
"name": "Ursidae",
"children": [
{
"id": 3,
"name": "Polar Bear",
"children": []
}
]
},
{
"name": "Canidae",
"children": [
{
"id": 4,
"name": "Labradore Retriever",
"children": []
},
{
"id": 5,
"name": "Golden Retriever",
"children": []
}
]
}
]
}
]
}
I've tried several approaches of grouping the dataframe and also looping over individual rows, but haven't been able to find a working solution yet. Any help would be greatly appreciated!
The answer of #Timus mimics your intention, however you might encounter some difficulties searching this dictionary as each level has a key name and a key children. If this is what you intended ignore my answer. However, if you would like to create a dictionary in which you can more easily search through unique keys you can try:
df = df.set_index(['level_1', 'level_2', 'level_3', 'level_4'])
def make_dictionary(df):
if df.index.nlevels == 1:
return df.to_dict()
dictionary = {}
for key in df.index.get_level_values(0).unique():
sub_df = df.xs(key)
dictionary[key] = df_to_dict(sub_df)
return dictionary
make_dictionary(df)
It requires setting the different levels as index, and you will end up with a slightly different dictionary:
{'Animals':
{'Carnivores':
{'Felidae':
{'id': {'Siamese Cat': 1,
'Javanese Cat': 2}},
'Ursidae':
{'id': {'Polar Bear': 3}},
'Canidae':
{'id': {'Labradore Retriever': 4,
'Golden Retriever': 5}}}
}
}
EDIT: Had to make an adjustment, because the result wasn't exactly as expected.
Here's an attempt that produces the expected output (if I haven't made a mistake, which wouldn't be a surprise, because I've made several on the way):
def pack_level(df):
if df.columns[0] == 'id':
return [{'id': i, 'name': name, 'children': []}
for i, name in zip(df[df.columns[0]], df[df.columns[1]])]
return [{'name': df.iloc[0, 0],
'children': [entry for lst in df[df.columns[1]]
for entry in lst]}]
df = pd.DataFrame(data)
columns = list(df.columns[1:])
df = df.groupby(columns[:-1]).apply(pack_level)
for i in range(1, len(columns) - 1):
df = (df.reset_index(level=-1, drop=False).groupby(columns[:-i])
.apply(pack_level)
.reset_index(level=-1, drop=True))
var_data = {'name': df.index[0], 'children': df.iloc[0]}
The result looks a bit different at first glance, but that should be only due to the sorting (from printing):
{
"children": [
{
"children": [
{
"children": [
{
"children": [],
"id": 4,
"name": "Labradore Retriever"
},
{
"children": [],
"id": 5,
"name": "Golden Retriever"
}
],
"name": "Canidae"
},
{
"children": [
{
"children": [],
"id": 1,
"name": "Siamese Cat"
},
{
"children": [],
"id": 2,
"name": "Javanese Cat"
}
],
"name": "Felidae"
},
{
"children": [
{
"children": [],
"id": 3,
"name": "Polar Bear"
}
],
"name": "Ursidae"
}
],
"name": "Carnivores"
}
],
"name": "Animals"
}
I've tried to be as generic as possible, but the first column has to be named id (as in your sample).
I am having the following problem.
class Inventory:
def __init__(self,project_no,country,category,product,count):
self.project_no = project_no
self.country = country
self.category = category
self.product = product
self.count = count
inventory_list = []
inventory_list.append(Inventory(1,'USA','Beverages','Milk',2))
inventory_list.append(Inventory(1,'USA','Beverages','Juice',5))
inventory_list.append(Inventory(1,'USA','Snacks','Potato Chips',2))
inventory_list.append(Inventory(1,'USA','Oils','Canola',5))
inventory_list.append(Inventory(1,'USA','Oils','Olive',8))
inventory_list.append(Inventory(1,'CAN','Beverages','Milk',7))
inventory_list.append(Inventory(1,'CAN','Beverages','Juice',8))
inventory_list.append(Inventory(1,'CAN','Snacks','Potato Chips',8))
inventory_list.append(Inventory(1,'CAN','Oils','Canola',3))
inventory_list.append(Inventory(1,'CAN','Oils','Olive',4))
{'Inventory': [{'Country': inv.country , 'Category' : [{inv.category : [{'Product' : inv.product}]}] } for inv in inventory_list]}
This code is giving me the following output.
{'Inventory': [{'Country': 'USA',
'Category': [{'Beverages': [{'Product': 'Milk'}]}]},
{'Country': 'USA', 'Category': [{'Beverages': [{'Product': 'Juice'}]}]},
{'Country': 'USA', 'Category': [{'Snacks': [{'Product': 'Potato Chips'}]}]},
{'Country': 'USA', 'Category': [{'Oils': [{'Product': 'Canola'}]}]},
{'Country': 'USA', 'Category': [{'Oils': [{'Product': 'Olive'}]}]},
{'Country': 'CAN', 'Category': [{'Beverages': [{'Product': 'Milk'}]}]},
{'Country': 'CAN', 'Category': [{'Beverages': [{'Product': 'Juice'}]}]},
{'Country': 'CAN', 'Category': [{'Snacks': [{'Product': 'Potato Chips'}]}]},
{'Country': 'CAN', 'Category': [{'Oils': [{'Product': 'Canola'}]}]},
{'Country': 'CAN', 'Category': [{'Oils': [{'Product': 'Olive'}]}]}]}
What I actually need is more like below.
{
"Inventory": [{
"country": "USA",
"category": [{
"Beverages": [{
"product": "Milk",
"count": 2
}, {
"product": "Juice",
"count": 5
}]
}, {
"Snacks": [{
"product": "Potato Chips",
"count": 2
}]
}, {
"Oils": [{
"product": "Canola",
"count": 5
}, {
"product": "Olive",
"count": 8
}]
}]
}, {
"country": "CAN",
"category": [{
"Beverages": [{
"product": "Milk",
"count": 7
}, {
"product": "Juice",
"count": 8
}]
}, {
"Snacks": [{
"product": "Potato Chips",
"count": 8
}]
}, {
"Oils": [{
"product": "Canola",
"count": 3
}, {
"product": "Olive",
"count": 4
}]
}]
}
]
}
How to do this?
I thought list comprehension is the way to go.
But I am having trouble beyond this point.
I thought this should be really easy for a python coder.
With my limited python I could only reach this far.
If anyone can help.
I would suggest you try serializing your Inventory class using the json module. However, it looks like you'll want to reorganize your data a bit. From what I can tell, you want to have an inventory that has a collection of countries which contain a set of products separated into categories.
First, let's define the Product class:
class Product(object):
def __init__(self, name, count):
self.product = name
self.count = count
Next, we can define the Country class as a container for a set Products, arranged in a dictionary using the category name as the key.
class Country(object):
def __init__(self, name):
self.name = name
self.categories = dict()
def add_product_to_category(self, category, product):
if category not in self.categories:
self.categories[category] = []
self.categories[category].append(product)
Then, we can re-define the Inventory class as a container for a set of Country objects.
class Inventory(object):
def __init__(self, project_no):
self.project_no = project_no
self.countries = []
Next, we can use simple methods to fill out our classes with the required data.
inv = Inventory(1)
us_set = Country('USA')
us_set.add_product_to_category('Beverages', Product('Milk', 2))
us_set.add_product_to_category('Beverages', Product('Juice', 5))
us_set.add_product_to_category('Snacks', Product('Potato Chips', 2))
us_set.add_product_to_category('Oils', Product('Canola', 5))
us_set.add_product_to_category('Oils', Product('Olive', 8))
canada_set = Country('CAN')
canada_set.add_product_to_category('Beverages', Product('Milk', 7))
canada_set.add_product_to_category('Beverages', Product('Juice', 8))
canada_set.add_product_to_category('Snacks', Product('Potato Chips', 8))
canada_set.add_product_to_category('Oils', Product('Canola', 3))
canada_set.add_product_to_category('Oils', Product('Olive', 4))
inv.countries.append(us_set)
inv.countries.append(canada_set)
Finally, (to actually answer your question, lul) to serialize the Inventory class, we have to define an encoder to use:
class MyEncoder(json.JSONEncoder):
def default(self, o):
return o.__dict__
Now, we can just call json.dumps() to get a string output of our serialized Inventory.
json.dumps(inv, indent=2, cls=MyEncoder)
The output isn't exactly what you laid out, but I think this method will work well for you.
{
"project_no": 1,
"countries": [
{
"name": "USA",
"categories": {
"Beverages": [
{
"count": 2,
"product": "Milk"
},
{
"count": 5,
"product": "Juice"
}
],
"Oils": [
{
"count": 5,
"product": "Canola"
},
{
"count": 8,
"product": "Olive"
}
],
"Snacks": [
{
"count": 2,
"product": "Potato Chips"
}
]
}
},
{
"name": "CAN",
"categories": {
"Beverages": [
{
"count": 7,
"product": "Milk"
},
{
"count": 8,
"product": "Juice"
}
],
"Oils": [
{
"count": 3,
"product": "Canola"
},
{
"count": 4,
"product": "Olive"
}
],
"Snacks": [
{
"count": 8,
"product": "Potato Chips"
}
]
}
}
]
}
try using the json module, e.g.
import json
...
inv_json = {'Inventory': [{'Country': inv.country , 'Category' : [{inv.category : [{'Product' : inv.product}]}] } for inv in inventory_list]}
json_formatted_str = json.dumps(x, indent=2)
print(json_formatted_str)
https://www.journaldev.com/33302/python-pretty-print-json