Consider a basic adjacency list; a list of nodes represent by a Node class, with properties id, parent_id, and name. The parent_id of top-level nodes = None.
What would be a Pythonic way of transforming the list into an un-ordered html menu tree, e.g.:
node name
node name
sub-node name
sub-node name
Assuming you've got something like this:
data = [
{ 'id': 1, 'parent_id': 2, 'name': "Node1" },
{ 'id': 2, 'parent_id': 5, 'name': "Node2" },
{ 'id': 3, 'parent_id': 0, 'name': "Node3" },
{ 'id': 4, 'parent_id': 5, 'name': "Node4" },
{ 'id': 5, 'parent_id': 0, 'name': "Node5" },
{ 'id': 6, 'parent_id': 3, 'name': "Node6" },
{ 'id': 7, 'parent_id': 3, 'name': "Node7" },
{ 'id': 8, 'parent_id': 0, 'name': "Node8" },
{ 'id': 9, 'parent_id': 1, 'name': "Node9" }
]
This function iterates through the list and creates the tree, collecting children of each node is the sub list:
def list_to_tree(data):
out = {
0: { 'id': 0, 'parent_id': 0, 'name': "Root node", 'sub': [] }
}
for p in data:
out.setdefault(p['parent_id'], { 'sub': [] })
out.setdefault(p['id'], { 'sub': [] })
out[p['id']].update(p)
out[p['parent_id']]['sub'].append(out[p['id']])
return out[0]
Example:
tree = list_to_tree(data)
import pprint
pprint.pprint(tree)
If parent ids are None's (not 0's), modify the function like this:
def list_to_tree(data):
out = {
'root': { 'id': 0, 'parent_id': 0, 'name': "Root node", 'sub': [] }
}
for p in data:
pid = p['parent_id'] or 'root'
out.setdefault(pid, { 'sub': [] })
out.setdefault(p['id'], { 'sub': [] })
out[p['id']].update(p)
out[pid]['sub'].append(out[p['id']])
return out['root']
# or return out['root']['sub'] to return the list of root nodes
This is how I ended up implementing it- #thg435's way is elegant, but builds a list of dictionaries to print. This one will print an actual HTML UL menu tree:
nodes = [
{ 'id':1, 'parent_id':None, 'name':'a' },
{ 'id':2, 'parent_id':None, 'name':'b' },
{ 'id':3, 'parent_id':2, 'name':'c' },
{ 'id':4, 'parent_id':2, 'name':'d' },
{ 'id':5, 'parent_id':4, 'name':'e' },
{ 'id':6, 'parent_id':None, 'name':'f' }
]
output = ''
def build_node(node):
global output
output += '<li><a>'+node['name']+'</a>'
build_nodes(node['id']
output += '</li>'
def build_nodes(node_parent_id):
global output
subnodes = [node for node in nodes if node['parent_id'] == node_parent_id]
if len(subnodes) > 0 :
output += '<ul>'
[build_node(subnode) for subnode in subnodes]
output += '</ul>'
build_nodes(None) # Pass in None as a parent id to start with top level nodes
print output
You can see it here: http://ideone.com/34RT4
Mine uses recursion (cool) and a global output string (not cool)
Someone could surely improve on this, but it's working for me right now..
Related
Hi i have an array of objects like below,
"output": [
{
'id': 1,
'items': [
{
'id':'1',
'data': {
'id': 3,
}
},
{
'id': '2',
'data': {
'id': 4,
}
}
]
},
{
'id': 2,
'items': [
{
'id':'3',
'data': {
'id': 5,
}
},
]
},
]
I want to retrieve the id property of items array and put it an array so the expected output is ['1','2','3']
below code works in javascript
arr_obj.map(obj=>obj.items.map(item=>item.id)).flat()
how can i do the above in python and django. could someone help me with this. I am new to python and django thanks.
Edit:
An example of how the logging the data in console looks.
output '[{'id': 1,'items': [{'id': 14, 'data': {'id': 1,}],}]'
You can work with list comprehension:
>>> [i['id'] for d in data for i in d['items']]
['1', '2', '3']
where data is the list of dictionaries.
I have source_json data looking like this:
{
'ID': {
'0': 8573273,
'1': 8573277
},
'prediction': {
'0': 4.411029362081518,
'1': 4.411029362081518
},
'feature': {
'0': 0,
'1': 0
}
}
But I need it to be in this form:
[
{
'ID': 8573273,
'prediction': 4.411029362081518,
'feature': 0
},
{
'ID': 8573277,
'prediction': 4.411029362081518,
'feature': 0
}
]
I convert the first view to Pandas dataframe and then convert it to the desirable json.
t = pd.DataFrame(source_json)
proper_jsone = t.to_dict(orient='records')
The question is: Is there a proper way to do this without creating an additional dataframe?
I prefer traditional way:
all_keys = list(source_json.keys())
all_indices = list(source_json[all_keys[0]].keys())
transformed_json = [ {_k:source_json[_k][_idx] for _k in all_keys} for _idx in all_indices]
You can try list comprehension
[{'ID':i, 'prediction':j, 'feature':k}
for i,j,k in zip(*[i.values() for i in d.values()]) ]
output
[{'ID': 8573273, 'prediction': 4.411029362081518, 'feature': 0},
{'ID': 8573277, 'prediction': 4.411029362081518, 'feature': 0}]
I need to extract 2 values from this list of dictionary and store it as a key-value pair.
Here I attached sample data..Where I need to extract "Name" and "Service" from this input and store it as a dictionary. Where "Name" is Key and corresponding "Service" is its value.
Input:
response = {
'Roles': [
{
'Path': '/',
'Name': 'Heera',
'Age': '25',
'Policy': 'Policy1',
'Start_Month': 'January',
'PolicyDocument':
{
'Date': '2012-10-17',
'Statement': [
{
'id': '',
'RoleStatus': 'New_Joinee',
'RoleType': {
'Service': 'Service1'
},
'Action': ''
}
]
},
'Duration': 3600
},
{
'Path': '/',
'Name': 'Prem',
'Age': '40',
'Policy': 'Policy2',
'Start_Month': 'April',
'PolicyDocument':
{
'Date': '2018-11-27',
'Statement': [
{
'id': '',
'RoleStatus': 'Senior',
'RoleType': {
'Service': ''
},
'Action': ''
}
]
},
'Duration': 2600
},
]
}
From this input, I need output as a dictionary type.
Output Format: { Name : Service }
Output:
{ "Heera":"Service1","Prem" : " "}
My try:
Role_name =[]
response = {#INPUT WHICH I SPECIFIED ABOVE#}
roles = response['Roles']
for role in roles:
Role_name.append(role['Name'])
print(Role_name)
I need to pair the name with its corresponding service. Any help would be really appreciable.
Thanks in advance.
You just have to write a long line which can reach till the key 'Service'.
And you a syntax error in line Start_Month': 'January') and 'Start_Month': 'April'). You can't have one unclosed brackets.
Fix it and run the following.
This is the code:
output_dict = {}
for r in response['Roles']:
output_dict[r["Name"]] = r['PolicyDocument']['Statement'][0]['RoleType']['Service']
print(output_dict)
Output:
{'Heera': 'Service1', 'Prem': ''}
You just have to do like this:
liste = []
for role in response['Roles']:
liste.append(
{
role['Name']:role['PolicyDocument']['Statement'][0]['RoleType']['Service'],
}
)
print(liste)
It seems your input data is structured kind of strange and I am not sure what the ) are doing next to the months since they make things invalid but here is a working script assuming you removed the parenthesis from your input.
response = {
'Roles': [
{
'Path': '/',
'Name': 'Heera',
'Age': '25',
'Policy': 'Policy1',
'Start_Month': 'January',
'PolicyDocument':
{
'Date': '2012-10-17',
'Statement': [
{
'id': '',
'RoleStatus': 'New_Joinee',
'RoleType': {
'Service': 'Service1'
},
'Action': ''
}
]
},
'Duration': 3600
},
{
'Path': '/',
'Name': 'Prem',
'Age': '40',
'Policy': 'Policy2',
'Start_Month': 'April',
'PolicyDocument':
{
'Date': '2018-11-27',
'Statement': [
{
'id': '',
'RoleStatus': 'Senior',
'RoleType': {
'Service': ''
},
'Action': ''
}
]
},
'Duration': 2600
},
]
}
output = {}
for i in response['Roles']:
output[i['Name']] = i['PolicyDocument']['Statement'][0]['RoleType']['Service']
print(output)
This should give you what you want in a variable called role_services:
role_services = {}
for role in response['Roles']:
for st in role['PolicyDocument']['Statement']:
role_services[role['Name']] = st['RoleType']['Service']
It will ensure you'll go through all of the statements within that data structure but be aware you'll overwrite key-value pairs as you traverse the response, if they exist in more than a single entry!
A reference on for loops which might be helpful, illustrates using if statements within them which can help you to extend this to check if items already exist!
Hope that helps
I'm trying to learn python. Assuming I have the below two dict().
In the 1st dict, it includes user info and the reporting line structures.
In the 2nd dict, it includes item counts belong to each individual.
I want to compare again these two dict and sum up the total item counts then display the result under name_S. The outcome is shown as follow:
data_set_1 = { 'id': 'mid',
'name': 'name_S',
'directory': [
{
'id': 'eid_A',
'name': 'name_A',
'directory': []
},
{ 'id': 'eid_B',
'name': 'name_B',
'directory': []
},
{ 'id': 'eid_C',
'name': 'name_C',
'directory': [
{'id': 'eid_C1',
'name': 'name_C1',
'directory': []},
{'id': 'eid_C2',
'name': 'name_C2',
'directory': []}]
}]}
data_set_2 = { 'eid_A': 5,
'eid_F': 3,
'eid_G': 0,
'eid_C': 1,
'eid_C1': 10,
'eid_C2': 20
}
Result:
{'name_S': 36}
I'm able to get the result if I did this way:
def combine_compare(data_set_1, data_set_2):
combine_result = dict()
combine_id = data_set_1['id']
combine_name = data_set_1['name']
combine_directory = data_set_1['directory']
if combine_directory:
combine_item_sum = 0
combine_item_count = data_set_2.get(combine_id, 0)
for combine_user in combine_directory:
# Recursion starts
for i in [combine_compare(combine_user, data_set_2)]:
for key, value in i.items():
combine_item_sum += value
combine_result[combine_name] = combine_item_sum + combine_item_count
else:
combine_result[combine_name] = data_set_2.get(combine_id, 0)
return combine_result
Now if I want to include the ids that have item counts in the final result, something like this:
#if there is result and directory is not None under name_S
{'name_S': [36, ('eid_A', 'eid_C', eid_C1', 'eid_C2')]}
#if there is no result and directory is not None under name_S, display a default str
{'name_S': [0, ('Null')]}
#if there is result and directory is None under name_S, display name_S id
{'name_S': [1, ('mid')]}
My original idea is to create a list and append the counts and ids but I'm struggling how I can accomplish this. Here is what I try but the list is not returning the outcome I'm expecting and I'm not sure how I can append the count in the list. Any help would be greatly appreciated.
def combine_compare(data_set_1, data_set_2):
combine_result = dict()
# Creating a new list
combine_list = list()
combine_id = data_set_1['id']
combine_name = data_set_1['name']
combine_directory = data_set_1['directory']
if combine_directory:
combine_item_sum = 0
combine_item_count = data_set_2.get(combine_id, 0)
for combine_user in combine_directory:
# Recursion starts
for i in [combine_compare(combine_user, data_set_2)]:
for key, value in i.items():
combine_item_sum += value
# Trying to append the ids where count > 0
if data_set_2.get(combine_user['id'], 0) != 0:
combine_list.append(combine_user['id'])
combine_result[combine_name] = combine_item_sum + combine_item_count
else:
combine_result[combine_name] = data_set_2.get(combine_id, 0)
# Trying to print the list to see the results
print(combine_list)
return combine_result
So what i understood from your question is that you want to know which ids mentioned in data_set_2 are there in data_set_1 and what is there sum. The following code is my version of solving the above mentioned problem.
data_set_1 = { 'id': 'mid',
'name': 'name_S',
'directory': [
{
'id': 'eid_A',
'name': 'name_A',
'directory': []
},
{ 'id': 'eid_B',
'name': 'name_B',
'directory': []
},
{ 'id': 'eid_C',
'name': 'name_C',
'directory': [
{'id': 'eid_C1',
'name': 'name_C1',
'directory': []},
{'id': 'eid_C2',
'name': 'name_C2',
'directory': []
}
]
}
]
}
data_set_2 = { 'eid_A': 5,
'eid_F': 3,
'eid_G': 0,
'eid_C': 1,
'eid_C1': 10,
'eid_C2': 20
}
value = 0
final_result={}
def compare(d1,d2):
global value
temp_result={}
if d1['name'] not in temp_result:
temp_result[d1['name']]=[]
for items in d1['directory']:
if items['directory']:
temp_value=compare(items,d2)
temp_result[d1['name']].append(temp_value)
result=check_for_value(items,d2)
if result:
value+=result
temp_result[d1['name']].append(items['id'])
return temp_result
def check_for_value(d,d2):
if d['id'] in d2:
return d2[d['id']]
final_result=compare(data_set_1,data_set_2)
final_result['value']=value
print("final_result:",final_result)
Which gives you an output dict which tells you exactly under which name does those ids come under.
The output is as follows:
final_result: {'value': 36, 'name_S': ['eid_A', {'name_C': ['eid_C1', 'eid_C2']}, 'eid_C']}
You can change the structure of the final result to make it exactly how you want it to be. Let me know if you have any trouble understanding the program.
I have an array where I am trying to group the subarrays of the objects together if the key value pair is equal to userID.
Leaving me with one object, per userID with all the sub-arrays of that userID.
I can't seem to figure out how to do this, even after trawling through SO.
How do I group the subarrays where the userID's are the same?
(the data changes so I need to use a for loop)
Thanks for the help.
The array looks like this:
[
{
'name':'James',
'lastname':'Bond',
'userID': 1001,
'subarray':[
{
'color':'blue',
'animal':'dog'
}
]
},
{
'name':'James',
'lastname':'Bond',
'userID': 1001,
'subarray':[
{
'color':'red',
'animal':'cat'
}
]
},
{
'name':'Billy',
'lastname':'King',
'userID': 1004,
'subarray':[
{
'color':'green',
'animal':'fish'
}
]
}
]
I want to make the array like this:
[
{
'name':'James',
'lastname':'Bond',
'userID': 1001,
'subarray':[
{
'color':'blue',
'animal':'dog'
},
{
'color':'red',
'animal':'cat'
}
]
},
{
'name':'Billy',
'lastname':'King',
'userID': 1004,
'subarray':[
{
'color':'green',
'animal':'fish'
}
]
}
]
Using a simple iteration.
Ex:
result = {}
for item in data:
if item["userID"] not in result:
result[item["userID"]] = {'name':item["name"], 'lastname':item["lastname"],'userID': item["userID"],'subarray':[]}
result[item["userID"]]['subarray'].append(item["subarray"])
print(list(result.values()))
Output:
[{'lastname': 'Bond',
'name': 'James',
'subarray': [[{'animal': 'dog', 'color': 'blue'}],
[{'animal': 'cat', 'color': 'red'}]],
'userID': 1001},
{'lastname': 'King',
'name': 'Billy',
'subarray': [[{'animal': 'fish', 'color': 'green'}]],
'userID': 1004}]