I have a list of dictionary. I want to convert this list into dictionary using parent and child relation. I have try many time. But its difficult for me.
Thanks in advance for solving the problem.
Input =
data = [
{
"_id": 1,
"label": "Property",
"index": 1
},
{
"_id": 2,
"label": "Find Property",
"index": 1,
"parent_id": 1
},
{
"_id": 3,
"label": "Add Property",
"index": 2,
"parent_id": 1
},
{
"_id": 4,
"label": "Offer",
"index": 2
},
{
"_id": 5,
"label": "My Offer",
"index": 1,
"parent_id": 4
},
{
"_id": 6,
"label": "Accept",
"index": 1,
"parent_id": 5
}
]
I have a list of dictionary. I want to convert this list into dictionary using parent and child relation. I have try many time. But its difficult for me.
Thanks in advance for solving the problem.
Expected Output:
[
{
"_id": 1,
"label": "Property",
"index": 1,
"children" : [
{
"_id": 2,
"label": "Find Property",
"index": 1
},
{
"_id": 3,
"label": "Add Property",
"index": 2
}
]
},
{
"_id": 4,
"label": "Offer",
"index": 2,
"children" : [
{
"_id": 5,
"label": "My Offer",
"index": 1,
"children" : [
{
"_id": 6,
"label": "Accept",
"index": 1
}
]
}
]
},
]
I would do it like this. Keep in mind that this solution also affects the original data list.
parents = list()
# First, create a new dict where the key is property id and the value
# is the property itself.
indexed = {d["_id"]:d for d in data}
for id_, item in indexed.items():
# If a property doesn't have "parent_id" key it means that
# this is the root property, appending it to the result list.
if "parent_id" not in item:
parents.append(item)
continue
# Saving parent id for convenience.
p_id = item["parent_id"]
# Adding a children list if a parent doesn't have it yet.
if "children" not in indexed[p_id]:
indexed[p_id]["children"] = list()
indexed[p_id]["children"].append(item)
And the result is:
import pprint
pprint.pprint(parents)
[{'_id': 1,
'children': [{'_id': 2, 'index': 1, 'label': 'Find Property', 'parent_id': 1},
{'_id': 3, 'index': 2, 'label': 'Add Property', 'parent_id': 1}],
'index': 1,
'label': 'Property'},
{'_id': 4,
'children': [{'_id': 5,
'children': [{'_id': 6,
'index': 1,
'label': 'Accept',
'parent_id': 5}],
'index': 1,
'label': 'My Offer',
'parent_id': 4}],
'index': 2,
'label': 'Offer'}]
Related
I am working on Elastic Search (version 7.16) with Oython (version 3.6)
I have the below rows in Elastic Search:
{"owner": "john", "database": "postgres", "table": "sales_tab"},
{"owner": "hannah", "database": "mongodb", "table": "dept_tab"},
{"owner": "peter", "database": "mysql", "table": "new_tab"},
{"owner": "jim", "database": "postgres", "table": "cust_tab"},
{"owner": "lima", "database": "postgres", "table": "sales_tab"},
{"owner": "tory", "database": "oracle", "table": "store_tab"},
{"owner": "kane", "database": "mysql", "table": "trasit_tab"},
{"owner": "roma", "database": "mongodb", "table": "common_tab"},
{"owner": "ashley", "database": "mongodb", "table": "common_tab"},
With the below query:
{
"size": 0,
"aggs": {
"table_grouped": {
"terms": {
"field": "table",
"size": 100000
}
}
}
}
I get distinct table values, something like below:
{..., 'aggregations': {'table_grouped': {'doc_count_error_upper_bound': 0, 'sum_other_doc_count': 0,
'buckets': [{'key': 'sales_tab', 'doc_count': 3}, {'key': 'dept_tab', 'doc_count': 1},
{'key': 'new_tab', 'doc_count': 1}, {'key': 'cust_tab', 'doc_count': 1},
{'key': 'store_tab', 'doc_count': 1}, {'key': 'trasit_tab', 'doc_count': 1},
{'key': 'common_tab', 'doc_count': 2}]}}}
But what I actually want is:
{..., 'aggregations': {'table_grouped': {'doc_count_error_upper_bound': 0, 'sum_other_doc_count': 0,
'buckets': [{'key': 'sales_tab', 'doc_count': 2, "database": "postgres"}, {'key': 'dept_tab',
'doc_count': 1, "database": "mongodb"}, {'key': 'new_tab', 'doc_count': 1,
"database": "mysql"}, {'key': 'cust_tab', 'doc_count': 1, "database": "postgres"},
{'key': 'store_tab', 'doc_count': 1, "database": "oracle"}, {'key': 'trasit_tab', 'doc_count': 1, "database": "mysql"},
{'key': 'common_tab', 'doc_count': 2, "database": "mongodb"}}]}}}
I want to know from which database is this table coming from, not just {'key': 'sales_tab', 'doc_count': 2} like extra key: value of database {'key': 'sales_tab', 'doc_count': 2, "database": "postgres"} value in buckets result or any other solution which will give distinct table along with the database it is coming from.
How do I achieve it?
You can use sub aggregation for getting database name as shown below:
{
"size": 0,
"aggs": {
"table_grouped": {
"terms": {
"field": "table",
"size": 10
},
"aggs": {
"database": {
"terms": {
"field": "database",
"size": 10
}
}
}
}
}
}
This will generate response as shown below:
"aggregations": {
"table_grouped": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "common_tab",
"doc_count": 2,
"database": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "mongodb",
"doc_count": 2
}
]
}
},
{
"key": "sales_tab",
"doc_count": 2,
"database": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "postgres",
"doc_count": 2
}
]
}
},
{
"key": "cust_tab",
"doc_count": 1,
"database": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "postgres",
"doc_count": 1
}
]
}
},
{
"key": "dept_tab",
"doc_count": 1,
"database": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "mongodb",
"doc_count": 1
}
]
}
},
{
"key": "new_tab",
"doc_count": 1,
"database": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "mysql",
"doc_count": 1
}
]
}
},
{
"key": "store_tab",
"doc_count": 1,
"database": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "oracle",
"doc_count": 1
}
]
}
},
{
"key": "trasit_tab",
"doc_count": 1,
"database": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "mysql",
"doc_count": 1
}
]
}
}
]
}
}
hopefully he the title is not too confusing, I have a dictionary (sample below) whereby im trying to sort the dictionary by the number of list (dictionary items) across a number of key values beneath a parent. Hopefully the example makes more sense then my description?
{
"data": {
"London": {
"SHOP 1": [
{
"kittens": 10,
"type": "fluffy"
},
{
"puppies": 11,
"type": "squidgy"
}
],
"SHOP 2": [
{
"kittens": 15,
"type": "fluffy"
},
{
"puppies": 3,
"type": "squidgy"
},
{
"fishes": 132,
"type": "floaty"
}
]
},
"Manchester": {
"SHOP 1": [
{
"kittens": 10,
"type": "fluffy"
},
{
"puppies": 11,
"type": "squidgy"
}
],
"SHOP 2": [
{
"kittens": 15,
"type": "fluffy"
},
{
"puppies": 3,
"type": "squidgy"
},
{
"fishes": 132,
"type": "floaty"
}
],
"SHOP 3": [
{
"kittens": 15,
"type": "fluffy"
},
{
"puppies": 3,
"type": "squidgy"
},
]
},
"Edinburgh": {
"SHOP 1": [
{
"kittens": 10,
"type": "fluffy"
},
{
"puppies": 11,
"type": "squidgy"
}
],
"SHOP 2": [
{
"kittens": 15,
"type": "fluffy"
},
],
"SHOP 3": [
{
"puppies": 3,
"type": "squidgy"
},
]
}
}
}
Summary
# London 2 shops, 5 item dictionaries total
# Machester 3 shops, 7 item dictionaries total
# Edinburgh 3 shops, 4 item dictionaries total
Desired sorting would be by total items across the shops, so ordered Manchester, London, Edinburgh
id usually use somethign like the below to sort, but im not sure how to do this oen with it being counting the number of items across a number of keys?
{k: v for k, v in sorted(x.items(), key=lambda item: item[1])}
You need to reverse sort based on the total number of items for each location, which you can generate as:
sum(len(i) for i in s.values())
where s is the shop dictionary for each location.
Putting this into a sorted expression:
dict(sorted(d['data'].items(), key=lambda t:sum(len(i) for i in t[1].values()), reverse=True))
gives:
{
'Manchester': {
'SHOP 1': [{'kittens': 10, 'type': 'fluffy'}, {'puppies': 11, 'type': 'squidgy'}],
'SHOP 2': [{'kittens': 15, 'type': 'fluffy'}, {'puppies': 3, 'type': 'squidgy'}, {'fishes': 132, 'type': 'floaty'}],
'SHOP 3': [{'kittens': 15, 'type': 'fluffy'}, {'puppies': 3, 'type': 'squidgy'}]
},
'London': {
'SHOP 1': [{'kittens': 10, 'type': 'fluffy'}, {'puppies': 11, 'type': 'squidgy'}],
'SHOP 2': [{'kittens': 15, 'type': 'fluffy'}, {'puppies': 3, 'type': 'squidgy'}, {'fishes': 132, 'type': 'floaty'}]
},
'Edinburgh': {
'SHOP 1': [{'kittens': 10, 'type': 'fluffy'}, {'puppies': 11, 'type': 'squidgy'}],
'SHOP 2': [{'kittens': 15, 'type': 'fluffy'}], 'SHOP 3': [{'puppies': 3, 'type': 'squidgy'}]
}
}
No need to make things complex:
adict = adict['data']
result = []
for capital, value in adict.items():
shop_count = len(value)
items = sum([len(obj) for obj in value.values()])
result.append((capital, shop_count, items))
for capital, shop_count, items in sorted(result, key=lambda x: x[2], reverse=True):
print(f'{capital} {shop_count} shops, {items} item dictionaries total')
Output:
Manchester 3 shops, 7 item dictionaries total
London 2 shops, 5 item dictionaries total
Edinburgh 3 shops, 4 item dictionaries total
I have specific format of list containing complex dictionary & containing again list of dictionaries (Nested Format), e.g.
And Requirement is to remove question_id from all associate dictionaries.
options = [
{
"value": 1,
"label": "Paints",
"question_id": "207",
"question": "Which Paint Brand?",
"question_type_id": 2,
"options": [
{
"value": 2,
"label": "Glidden",
"question": "Is it Glidden Paint?",
"question_id": 1,
"options": [{"question_id": 1,"value": 10000, "label": "No"}, {"question_id": 1,"value": 10001, "label": "Yes"}],
},
{
"value": 1,
"label": "Valspar",
"question": "Is it Valspar Paint?",
"question_id": 1,
"options": [{"question_id": 1,"value": 10000, "label": "No"}, {"question_id": 1,"value": 10001, "label": "Yes"}],
},
{
"value": 3,
"label": "DuPont",
"question": "Is it DuPont Paint?",
"question_id": 1,
"options": [{"question_id": 1,"value": 10000, "label": "No"}, {"question_id": 1,"value": 10001, "label": "Yes"}],
},
],
},
{
"value": 4,
"label": "Rods",
"question": "Which Rods Brand?",
"question_id": 2,
"options": [
{"value": 3, "label": "Trabucco"},
{"value": 5, "label": "Yuki"},
{"value": 1, "label": "Shimano"},
{"value": 4, "label": "Daiwa"},
{"value": 2, "label": "Temple Reef"},
],
},
{
"value": 3,
"label": "Metal Sheets",
"question": "Which Metal Sheets Brand?",
"question_id": 2,
"options": [
{"value": 2, "label": "Nippon Steel Sumitomo Metal Corporation"},
{"value": 3, "label": "Hebei Iron and Steel Group"},
{"value": 1, "label": "ArcelorMittal"},
],
},
{
"value": 2,
"label": "Door Knobs Locks",
"question": "Which Door Knobs Locks Brand?",
"question_id": 2,
"options": [
{
"value": 1,
"label": "ASSA-Abloy",
"question": "Is it ASSA-Abloy Door Knobs Locks?",
"question_type_id": 1,
"options": [{"value": 10000, "label": "No"}, {"value": 10001, "label": "Yes"}],
},
{
"value": 4,
"label": "RR Brink",
"question": "Is it RR Brink Door Knobs Locks?",
"question_type_id": 1,
"options": [{"value": 10000, "label": "No"}, {"value": 10001, "label": "Yes"}],
},
{
"value": 3,
"label": "Medeco",
"question": "Is it Medeco Door Knobs Locks?",
"question_type_id": 1,
"options": [{"value": 10000, "label": "No"}, {"value": 10001, "label": "Yes"}],
},
{
"value": 2,
"label": "Evva",
"question": "Is it Evva Door Knobs Locks?",
"question_type_id": 1,
"options": [{"value": 10000, "label": "No"}, {"value": 10001, "label": "Yes"}],
},
],
},
]
For this I have written a code & trying to run it recursively.
from collections import MutableMapping
def delete_keys_from_dict(dictionary_list, keys):
keys_set = set(keys) # Just an optimization for the "if key in keys" lookup.
# modified_list=[]
for index, dictionary in enumerate(dictionary_list):
modified_dict = {}
for key, value in dictionary.items():
if key not in keys_set:
if isinstance(value, list):
modified_dict[key] = delete_keys_from_dict(value, keys_set)
else:
if isinstance(value, MutableMapping):
modified_dict[key] = delete_keys_from_dict(value, keys_set)
else:
modified_dict[key] = value
# or copy.deepcopy(value) if a copy is desired for non-dicts.
dictionary_list[index] = modified_dict
return dictionary_list
It's returning incorrect list & which is not preserving the existing list data.
May i know, Where am i going wrong or missing something somewhere?
I think something like this should do what you want.
obj may be any object, and this recurses into lists and dicts.
def delete_keys(obj, keys):
if isinstance(obj, list):
return [
delete_keys(item, keys)
for item in obj
]
if isinstance(obj, dict):
return {
key: delete_keys(value, keys)
for (key, value) in obj.items()
if key not in keys
}
return obj # Nothing to do for this value
e.g.
from pprint import pprint
options = [
{
"value": 1,
"label": "Paints",
"question_id": "207",
"question": "Which Paint Brand?",
"question_type_id": 2,
"options": [
{
"value": 2,
"label": "Glidden",
"question": "Is it Glidden Paint?",
"question_id": 1,
"options": [{"question_id": 1,"value": 10000, "label": "No"}, {"question_id": 1,"value": 10001, "label": "Yes"}],
}
],
},
{
"value": 4,
"label": "Rods",
"question": "Which Rods Brand?",
"question_id": 2,
"options": [
{"value": 3, "label": "Trabucco"},
{"value": 5, "label": "Yuki"},
{"value": 1, "label": "Shimano"},
{"value": 4, "label": "Daiwa"},
{"value": 2, "label": "Temple Reef"},
],
},
]
pprint(delete_keys(options, {"question_id"}))
outputs
[{'label': 'Paints',
'options': [{'label': 'Glidden',
'options': [{'label': 'No', 'value': 10000},
{'label': 'Yes', 'value': 10001}],
'question': 'Is it Glidden Paint?',
'value': 2}],
'question': 'Which Paint Brand?',
'question_type_id': 2,
'value': 1},
{'label': 'Rods',
'options': [{'label': 'Trabucco', 'value': 3},
{'label': 'Yuki', 'value': 5},
{'label': 'Shimano', 'value': 1},
{'label': 'Daiwa', 'value': 4},
{'label': 'Temple Reef', 'value': 2}],
'question': 'Which Rods Brand?',
'value': 4}]
In a n-depth dict where values are set in the deepest level of a hierarchy:
{
"name": "root",
"value": None, # expected value to be 80
"children": [
{
"name": "a",
"value": None, # expected value to be 30
"children": [
{ "name": "a.1", "value": 10 },
{ "name": "a.2", "value": 20 }
]
},
{
"name": "b",
"value": None, # expected value to be 50
"children": [
{ "name": "b.1", "value": 25 },
{
"name": "b.2",
"value": None, # expected value to be 25
"children": [
{"name": "b.2.1", "value": 5},
{"name": "b.2.2", "value": 5},
{"name": "b.2.3", "value": 5},
{"name": "b.2.4", "value": 5},
{"name": "b.2.5", "value": 5}
]
}
]
}
]
}
What could be the approach to recursively set each parent value based on the result of an operation perfomed with its children value (i.e. sum)?
I finally managed to do it using the iterative level order traversal pattern (BFS), I was missing just a couple of details.
This approach works because the depth iteration order is guaranteed, so once we are getting to a node wich has children, all its sub-level children are already calculated.
The solution:
def reverseTraversal(obj):
def parentOperation(node):
out = 0
for child in node['children']:
out = out + child['value']
return out
if obj is None:
return
queue = []
stack = []
queue.append(obj)
while len(queue) > 0:
temp = queue.pop(0)
stack.append(temp)
if 'children' in temp and len(temp['children']) > 0:
for child in temp['children']:
queue.append(child)
while len(stack)>0:
node = stack.pop()
if 'children' in node and len(node['children']) > 0:
node['value'] = parentOperation(node)
# obj is the original dict
obj = reverseTraversal(obj)
print(obj)
Results in:
{
"name": "root",
"value": 80,
"children": [
{
"name": "a",
"value": 30,
"children": [
{"name": "a.1","value": 10},
{"name": "a.2","value": 20}
]
},
{
"name": "b",
"value": 50,
"children": [
{"name": "b.1","value": 25},
{
"name": "b.2",
"value": 25,
"children": [
{"name": "b.2.1","value": 5},
{"name": "b.2.2","value": 5},
{"name": "b.2.3","value": 5},
{"name": "b.2.4","value": 5},
{"name": "b.2.5","value": 5}
]
}
]
}
]
}
Given your datastructure and a list of values to update, you can use next in recursion:
def update(d, targets):
return {a:[update(i, targets) for i in b] if isinstance(b, list) else update(b, targets) if isinstance(b, dict) else next(targets) if not b else b for a, b in d.items()}
targets = [80, 30, 50, 25]
results = update(nlist, iter(targets))
Output:
{'children': [{'children': [{'name': 'a.1', 'value': 10},
{'name': 'a.2', 'value': 20}],
'name': 'a',
'value': 30},
{'children': [{'name': 'b.1', 'value': 25},
{'children': [{'name': 'b.2.1', 'value': 5},
{'name': 'b.2.2', 'value': 5},
{'name': 'b.2.3', 'value': 5},
{'name': 'b.2.4', 'value': 5},
{'name': 'b.2.5', 'value': 5}],
'name': 'b.2',
'value': 25}],
'name': 'b',
'value': 50}],
'name': 'root',
'value': 80}
I want to make a list of dictionary that way, every element which has a parent id, it should be child of the parent element.
Let's say we have a python list, which contains multiple dictionaries.
[{
"id": 1,
"title": "node1",
"parent": null
},
{
"id": 2,
"title": "node2",
"parent": 1
},
{
"id": 3,
"title": "node3",
"parent": 1
},
{
"id": 4,
"title": "node4",
"parent": 2
},
{
"id": 5,
"title": "node5",
"parent": 2
}]
And I want to convert this list to tree based on parent key. like,
[{
'id':1,
'title':'node1',
'childs':[
{
'id':2,
'title':'node2'
'childs':[
{
'id':4,
'title':'node4',
'childs': []
},
{
'id':5,
'title':'node5',
'childs': []
}
]
},
{
'id':3,
'title':'node3'
'childs':[]
}
]
}]
data = [{
"id": 1,
"title": "node1",
"parent": "null"
},
{ "id": 2,
"title": "node2",
"parent": "null"
},
{
"id": 2,
"title": "node2",
"parent": 1
},
{
"id": 3,
"title": "node3",
"parent": 1
},
{
"id": 4,
"title": "node4",
"parent": 2
},
{
"id": 5,
"title": "node5",
"parent": 2
}]
parent_data=[]
for keys in data:
if keys['parent'] == "null":
keys['childs']=[]
parent_data.append(keys)
for keys in data:
for key in parent_data:
if key['id'] == keys['parent']:
key['childs'].append(keys)
print parent_data
k = [{
"id": 1,
"title": "node1",
"parent": "null"
},
{
"id": 2,
"title": "node2",
"parent": 1
},
{
"id": 3,
"title": "node3",
"parent": 1
},
{
"id": 4,
"title": "node4",
"parent": 2
},
{
"id": 5,
"title": "node5",
"parent": 2
}]
result, t = [], {}
for i in k:
i['childs'] = []
if i['parent'] == 'null':
del i['parent']
result.append(i)
t[1] = result[0]
else:
t[i['parent']]['childs'].append(i)
t[i['id']] = t[i['parent']]['childs'][-1]
del t[i['parent']]['childs'][-1]['parent']
print result