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.
Related
I want to convert a data like below to QueryDict object. Is there a ready-made class that can do this job? I could not parse the data that came in the form of the "multipart/form-data" as I wanted. So I need help
data = {
'name': 'erhan',
'last_name': 'koçlar',
'gender.code': 1,
'gender1.gender2.gender3.gender4.code': 1,
'tags[5]': 'TAG_2',
'tags[0]': 'TAG_1',
'tags[1]': 'TAG_2',
'persons[0].name': 'erhan',
'persons[1].name': 'ercan',
'files[0].file': 'file1',
'files[0].name': 'file_name_1',
'section_files[0]': 'file2'
'rows[0][0]': 'col_1',
'rows[0][1]': 'col_2',
'rows[1][0]': 'row_1',
'rows[1][1]': 'row_2'
}
#after convert
data = {
'name':'erhan',
'last_name': 'koçlar',
'gender': { 'code': 1 },
'gender1': { 'gender2': { 'gender3': { 'gender4': { 'code': 1 } } } },
'tags': [ 'TAG_1', 'TAG_2', 'TAG_2' ],
'persons': [ {'name':'erhan'}, {'name':'ercan'} ],
'files': [ {'file': 'file1', 'name':'file_name_1' }],
'section_files': [ 'file2' ],
'rows': [ [ 'col_1', 'col_2' ], [ 'row_1', 'row_2' ] ],
}
Something like this can do the Job. Note the modification I changed files[0].name to files[1].name as it would overwrite the field 0.
import re
data = {
'name': 'erhan',
'last_name': 'koçlar',
'gender.code': 1,
'gender1.gender2.gender3.gender4.code': 1,
'tags[5]': 'TAG_2',
'tags[0]': 'TAG_1',
'tags[1]': 'TAG_2',
'persons[0].name': 'erhan',
'persons[1].name': 'ercan',
'files[0].file': 'file1',
'files[1].name': 'file_name_1',
'section_files[0]': 'file2',
'rows[0][0]': 'col_1',
'rows[0][1]': 'col_2',
'rows[1][0]': 'row_1',
'rows[1][1]': 'row_2'
}
def buildSubDict(dkey,value):
keys = dkey.split('.')
while keys:
cdict = {keys.pop():value}
value = cdict
return cdict
def buildArray(keys, uniqueName, data):
aSize = None
for key in keys:
match =re.findall('[(\d+)]',key)
m = [[int(m)] for m in match]
if not aSize:
aSize = m
else:
aSize = [a + b for a,b in zip(aSize,m)]
aSize = [max(i)+1 for i in aSize]
res = ''
while aSize:
res = [res if isinstance(res, str) else res.copy() for n in range(aSize.pop())]
for key in keys:
match =re.findall('[(\d+)]',key)
ndim = [int(m) for m in match]
templst = []
citem = res
for idx in ndim:
new = citem[idx]
if not isinstance(new, list):
citem[idx] = data[key]
data.pop(key)
break
citem = new
data[uniqueName]=res
newKeys = {}
for key in dict(data):
subkey = None
if '.' in key:
sDict = buildSubDict(key,data[key])
data[list(sDict.keys())[0]] = sDict[list(sDict.keys())[0]]
data.pop(key)
uniqueKeys = set([i.split('[')[0] for i in data.keys() if '[' in i ])
for ukey in uniqueKeys:
subkeys = []
for key in data:
if ukey+'[' in key:
subkeys.append(key)
buildArray(subkeys, ukey, data)
After processing, data will look like this:
{'name': 'erhan',
'last_name': 'koçlar',
'gender': {'code': 1},
'gender1': {'gender2': {'gender3': {'gender4': {'code': 1}}}},
'section_files': ['file2'],
'persons': [{'name': 'erhan'}, {'name': 'ercan'}],
'rows': [['col_1', 'col_2'], ['row_1', 'row_2']],
'tags': ['TAG_1', 'TAG_2', '', '', '', 'TAG_2'],
'files': [{'file': 'file1'}, {'name': 'file_name_1'}]}
Also note the different implementation of tags, compared to your question. You can filter out the '' by setting them to None instead and then do a list comprehension [i for i in myList if i] to filter them out.
I have extracted data from woocommerce webshop with api. Part of the top structure is like this:
{'id': 12345,
'attributes': [{'id': 1,
'name': 'kleur',
'position': 0,
'visible': True,
'variation': False,
'options': ['blauw']},
{'id': 2,
'name': 'maat',
'position': 1,
'visible': True,
'variation': True,
'options': ['s',
'm',
'l']}],
..................
}
try to make a list of dicts
all_webshop_skus = []
for item in all_data:
product= {}
product = {
'id':item['id'],
'sku': item['sku'],
'name' : item['name'],
'date_created': item['date_created'],
'brands': item['brands'][0]['name'],
'attributes': item['attributes'][1]['name']
}
all_webshop_skus.append(product)
iteration has index issues
---> 16 'attributes': item['attributes'][1]['name']
17 }
18 all_webshop_skus.append(product)
IndexError: list index out of range
IndexError: list index out of range
I think because not every item has a second element in the 'attributes' list of dicts. How can I extract 'name'_values from 'attributes' with 'attribute_id'_value = 2?
Loop through the attributes until you find the one you want, and use its name.
all_webshop_skus = []
for item in all_data:
for attr in item['attributes']:
if attr['id'] == 2:
name = attr['name']
break
else: # default if not found
name = ''
product = {
'id': item['id'],
'sku': item['sku'],
'name' : item['name'],
'date_created': item['date_created'],
'brands': item['brands'][0]['name'],
'attributes': name
}
all_webshop_skus.append(product)
I have a list of dictionaries in python3, that form a pyramid-type structure of 5 levels top, and i need to convert to a dictionary of dictionary in base to one value.
for example the list:
[ {'data': 'data', 'name': 'exampleName2', 'referal': 'exampleName1'},
{'data': 'data', 'name': 'exampleName3', 'referal': 'exampleName2'},
{'data': 'data', 'name': 'exampleName4', 'referal': 'exampleName3'}]
need to be converted to(every refered list could contain any number of items):
{ 'data': 'data',
'name': 'exampleName1',
'refered': [ { 'data': 'data',
'name': 'exampleName2',
'refered': [ { 'data': 'data',
'name': 'exampleName3',
'refered': [ { 'data': 'data',
'name': 'exampleName4',
'refered': [ ]}]}]}]}
I could do a lot of for and while loops, but i think there is a fast method. My method at the moment is:
try:
porOrdenar = LISTADO
ordenados = []
while len(porOrdernar) > 0:
n = 0
while n < len(porOrdernar):
if porOrdernar[n]["referal"]=="uno":
ordenados.append(porOrdernar[n])
porOrdernar.pop(n)
for element in ordenados:
unirReferidos(porOrdernar, n, element1)
for element1 in element["referidos"]:
unirReferidos(porOrdernar, n, element1)
for element2 in element1["referidos"]:
unirReferidos(porOrdernar, n, element2)
for element3 in element2["referidos"]:
unirReferidos(porOrdernar, n, element3)
n +=1
except IndexError:
pass
def unirReferidos(porOrdernar, n, element3):
if porOrdernar[n]["referal"] == element3["name"]:
element3["refered"].append(porOrdernar[n])
porOrdernar.pop(n)
I need to convert the dictionary to a json object, for that i preferer a dictionary.
data = [{"id": "78ab45",
"name": "Jonh"},
{"id": "69cd234457",
"name": "Joe"}]
I want my function to return the largest value lengths for each key from all dictionaries:
expected_output = [
{ "size": 10, "name": "id" }, #because the length of the largest "id" value is 10
{ "size": 4, "name": "name" }, #because the length of the largest "name" value is 4
]
My code so far:
def my_func(data):
headers_and_sizes = []
for item in data:
for key, value in item.items():
headers_and_sizes.append({"size": f'{len(value)}', "name": key})
if int(headers_and_sizes[0]["size"]) < len(value):
headers_and_sizes[0]["size"] = len(value)
return headers_and_sizes
Gives me this:
[{'size': '6', 'name': 'id'}, {'size': '4', 'name': 'name'}, {'size': '10', 'name': 'id'}, {'size': '3', 'name': 'name'}]
How can I fix that so that it will return the values as in expected_output?
You'll want to be updating a dictionary that stores each key mapped to the maximum length seen for that key thus far.
data = [
{
"id": "78ab45",
"name": "Jonh",
},
{
"id": "69cd234457",
"name": "Joe",
},
]
key_to_max_len = {}
for datum in data:
for key, val in datum.items():
if key not in key_to_max_len or len(val) > key_to_max_len[key]:
key_to_max_len[key] = len(val)
key_size_arr = [{"size": val, "name": key} for key, val in key_to_max_len.items()]
you can get the max value for id and name like below code, and structure the output accordingly
>>> data
[{'id': '78ab45', 'name': 'Jonh'}, {'id': '69cd234457', 'name': 'Joe'}]
id = max(map(lambda x:len(x['id']), data))
name = max(map(lambda x:len(x['name']), data))
>>> id
10
>>> name
4
You can use list comprehension to form a tuple with ids and names:
names_ids = [(eachdict['id'],eachdict['name']) for eachdict in data]
Format the output to have the desired shape (dictionaries), find the max length (using the max() function, passing it the lengths of names and ids, using another list comprehension, inside max()):
expected_output = \
[{"size":max([len(each[0]) for each in names_ids]),"name":"id"},
{"size":max([len(each[1]) for each in names_ids]),"name":"name"}]
Output will be:
[{'name': 'id', 'size': 10}, {'name': 'name', 'size': 4}]
Using the following:
keys = list(data[0].keys())
output = {key:-1 for key in keys}
for d in data:
for k in d.keys():
if len(d[k]) > output[k]:
output[k] = len(d[k])
Will output:
{'id': 10, 'name': 4}
I think the easiest method here is pandas...
import pandas as pd
df = pd.DataFrame(data)
out = [{'size': df['id'].str.len().max(), 'name':'id'},
{'size': df['name'].str.len().max(), 'name':'name'}]
output:
[{'size': 10, 'name': 'id'}, {'size': 4, 'name': 'name'}]
or for addt'l names..
[{'size':df[col].str.len().max(), 'name':col} for col in df.columns]
Here is how you can use a nested dictionary comprehension:
data = [{"id": "78ab45",
"name": "Jonh"},
{"id": "69cd234457",
"name": "Joe"}]
expected_output = [{'size': len(max([i[k] for i in data], key=len)),
'name': k} for k in data[0]]
print(expected_output)
Output:
[{'size': 10, 'name': 'id'},
{'size': 4, 'name': 'name'}]
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..