Input data:
data = [
['QR', ''],
['Cust', ''],
['fea', 'restroom'],
['chain', 'pa'],
['store', 'cd'],
['App', ''],
['End', 'EndnR'],
['Request', '0'],
['Sound', '15'],
['Target', '60'],
['Is', 'TRUE']
]
I want to turn this into a dictionary, and each blank value indicates the start of a new, nested sub-dictionary.
Desired output:
{
'QR': {
'Cust': {
'fea': 'restroom ',
'chain': 'pa',
'store': 'cd'
},
'App': {
'End': 'EndnR',
'Request': '0',
'Sound': '15',
'Target': '60',
'Is': 'true'
},
}
}
Here is my code so far:
from collections import defaultdict
res = defaultdict(dict)
for i in data:
res[i[0]] = i[1]
print(res)
But it only creates a flat dictionary with some blank values, not a nested dictionary.
try this:
result = {}
nbr_keys = 0
keys = [ item[0] for item in data if item[1] == "" ]
for index, item in enumerate(data):
if index == 0:
if item[1] == "":
key = item[0]
di[item[0]] = {}
else:
if item[1] == "":
di[key].update({item[0]: {}})
nbr_keys +=1
else:
di[key][keys[nbr_keys]].update({item[0]: item[1]})
which outputs this:
{'QR': {'Cust': {'fea': 'restroom', 'chain': 'pa', 'store': 'cd'},
'App': {'End': 'EndnR',
'Request': '0',
'Sound': '15',
'Target': '60',
'Is': 'TRUE'}}}
Related
Myd is below
{ 'Owner': [ { 'id': '1', 'name': 'John', 'contactEmail': 'john#nif.com', 'role': 'Owner' }, { 'id': '2', 'contactName': 'Work', 'contactEmail': 'work#nif.com', 'role': 'Owner' } ], 'Manager': [ { 'id': '1', 'name': 'John', 'contactEmail': 'john#nif.com', 'role': 'Manager' } ] }
Extract id to outside
Add entire dictionary into a new key called 'employee'
For the same key role are there in two different keys merge to one
id=1 role is present as Owner and Manager, output will role:['Manager', 'Owner']
Expected out
{ 'employee': { '1': { 'email': 'john#nif.com', 'name': 'John', 'role': [ 'Owner', 'Manager' ] }, '2': { 'email': 'work#nif.com', 'name': 'Work', 'role': [ 'Owner' ] } } }
emp = {}
for key,val in event.items():
for each in val:
# [{'employee': key, **val} for key, val in event.items()] if event else []
emp['employee'] = each['id']
emp['name'] = each['name']
using python native method
Here's a try without using third party lib:
myd = {
'Owner': [
{ 'id': '1', 'name': 'John', 'contactEmail': 'john#nif.com', 'role': 'Owner' },
{ 'id': '2', 'contactName': 'Work', 'contactEmail': 'work#nif.com', 'role': 'Owner' }
],
'Manager': [ { 'id': '1', 'name': 'John', 'contactEmail': 'john#nif.com', 'role': 'Manager' } ]
}
empl_dict = {}
for employees in myd.values():
for emp in employees:
emp_id = emp.pop('id')
emp_role = emp.pop('role')
empl_dict[emp_id] = empl_dict.get(emp_id, {})
empl_dict[emp_id].update(emp)
empl_dict[emp_id]['role'] = empl_dict[emp_id].get('role', [])
empl_dict[emp_id]['role'].append(emp_role)
all_employees = {'employee': empl_dict}
print(all_employees)
results in:
{'employee': {'1': {'name': 'John', 'contactEmail': 'john#nif.com', 'role': ['Owner', 'Manager']}, '2': {'contactName': 'Work', 'contactEmail': 'work#nif.com', 'role': ['Owner']}}}
You can use pandas to achieve this
Converting to pandas dataframe followed by groupby on contactEmail and aggregating results in required manner
df = pd.concat([pd.DataFrame(v).assign(key=k) for k,v in a.items()])
res = df.groupby('contactEmail').agg({'role':list,'name':'first'}).reset_index().T.to_dict()
{'employee':res}
out:
{'employee': {0: {'contactEmail': 'john#nif.com',
'role': ['Owner', 'Manager'],
'name': 'John'},
1: {'contactEmail': 'work#nif.com', 'role': ['Owner'], 'name': nan}}}
Edit:
if you want to achieve this in python
for OM in a.keys():
for ids in a[OM]:
ids['role'] = [OM]
total_recs = sum(list(a.values()),[])
res = {}
for rec in total_recs:
ID = rec['id']
if ID not in res.keys():
rec.pop('id')
res[ID] = rec
else:
rec.pop('id')
res[ID]['role'].extend(rec['role'])
{'employee':res}
Out:
{'employee': {'1': {'name': 'John',
'contactEmail': 'john#nif.com',
'role': ['Owner', 'Manager']},
'2': {'contactName': 'Work',
'contactEmail': 'work#nif.com',
'role': ['Owner']}}}
I have two lists of objects and I need to select the items that have the same attribute cpf and value:
This is my object class:
class Clientes:
def __init__(self):
self.nome = ""
self.cpf = ""
self.valor = ""
self.proposta = ""
And this my main code:
from objetos import Clientes
ArquivoA = {'Cliente1': ['Antonio', '123', '150', 'a'],
'Cliente2': ['Betina', '456', '200', 'b'],
'Cliente3': ['Dagmar', '789', '300', 'c'],
'Cliente4': ['Richard', '001', '400', 'd'],
'Cliente5': ['Maria', '435', '80', 'e']}
ArquivoB = {'Cliente1': ['Antonio', '123', '150'],
'Cliente2': ['Betina', '456', '200'],
'Cliente3': ['Dagmar', '789', '250'],
'Cliente4': ['Richard', '001', '450'],
'Cliente5': ['Jose', '987', '500']}
listaA= []
listaB = []
for item in ArquivoA:
c = Clientes()
c.nome = ArquivoA[item][0]
c.CPF = ArquivoA[item][1]
c.valor = ArquivoA[item][2]
c.proposta = ArquivoA[item][3]
listaA.append(c)
print(listaA)
for item in ArquivoB:
b = Clientes()
b.nome = ArquivoB[item][0]
b.CPF = ArquivoB[item][1]
b.valor = ArquivoB[item][2]
listaB.append(c)
print(listaB)
I want to create a new list where c.CPF == b.CPF and c.value == b.value. I don't want to use double loop for this, because my real list is so big.
Build dictionaries by your attributes of interest using dict comprehensions.
Find common keys using set intersections.
Now go and grab the values stored in the lookup dictionaries.
ArquivoA = {'Cliente1': ['Antonio', '123', '150', 'a'],
'Cliente2': ['Betina', '456', '200', 'b'],
'Cliente3': ['Dagmar', '789', '300', 'c'],
'Cliente4': ['Richard', '001', '400', 'd'],
'Cliente5': ['Maria', '435', '80', 'e']}
ArquivoB = {'Cliente1': ['Antonio', '123', '150'],
'Cliente2': ['Betina', '456', '200'],
'Cliente3': ['Dagmar', '789', '250'],
'Cliente4': ['Richard', '001', '450'],
'Cliente5': ['Jose', '987', '500']}
class Clientes:
def __init__(self, nome, CPF, valor, proposta=None):
self.nome = nome
self.CPF = CPF
self.valor = valor
self.proposta = proposta
def __repr__(self) -> str:
return f"{self.__dict__}"
list_a = [Clientes(v[0], v[1], v[2],v[3]) for v in ArquivoA.values()]
list_b = [Clientes(v[0], v[1], v[2]) for v in ArquivoB.values()]
#build a lookup dictionary by CPF, valor
di_a = {(c.CPF, c.valor) : c for c in list_a}
di_b = {(c.CPF, c.valor) : c for c in list_b}
#use sets to find common keys
set_a = set(di_a.keys())
set_b = set(di_b.keys())
common = set_a & set_b
#compare or do something else with the matching instances
for key in common:
va = di_a[key]
vb = di_b[key]
print(f"\n\n{key}:\n {va=}\n {vb=}" )
output:
('123', '150'):
va={'nome': 'Antonio', 'CPF': '123', 'valor': '150', 'proposta': 'a'}
vb={'nome': 'Antonio', 'CPF': '123', 'valor': '150', 'proposta': None}
('456', '200'):
va={'nome': 'Betina', 'CPF': '456', 'valor': '200', 'proposta': 'b'}
vb={'nome': 'Betina', 'CPF': '456', 'valor': '200', 'proposta': None}
I'm having issues trying to combine two lists that I have, Username and Account into a dictionary(username being the key and account being the value). My issue is I want any value with the same key to be added together(i.e the Brandon would only show up once with a value of 115.5). I would also like to skip the key/value pair for any blank or non-number values. Any help would be appreciated.
username = ['Brandon', 'Patrick', 'Brandon', 'Jack', '', 'Sarah', 'Jack', 'Brandon', 'James', 'James', 'Sarah', '', 'Brandon']
account = ['5', '18.9', 'xyz', '', '', '825', '45', '10', '3.25', '125.62', '2.43', '', '100.5']
You can zip together corresponding elements. Skip invalid values by catching errors on conversion to float, and use the falsiness of empty strings to skip empty keys
names = {}
for k, v in zip(username, account):
# check for empty keys
if not k:
continue
# an error on float conversion is due to a non
# numeric string (float or int)
try:
v = float(v)
except:
continue
# if the key is not in names, then .get will return
# 0, otherwise the last value set
names[k] = names.get(k, 0) + v
names
{'Brandon': 115.5, 'Patrick': 18.9, 'Sarah': 827.43, 'Jack': 45.0, 'James': 128.87}
How about this?
The more advanced things you may want to look up are: defaultdict and zip
from collections import defaultdict
username = ['Brandon', 'Patrick', 'Brandon', 'Jack', '', 'Sarah', 'Jack', 'Brandon', 'James', 'James', 'Sarah', '', 'Brandon']
account = ['5', '18.9', 'xyz', '', '', '825', '45', '10', '3.25', '125.62', '2.43', '', '100.5']
result = defaultdict(list)
for u, a in zip(username, account):
if a != '':
result[u].append(a)
You can use zip. all with check the conditions if not '' and value is not numeric.
from collections import defaultdict
d = defaultdict(float)
for i in zip(username, account):
if all([*i, i[1].replace('.','').isdigit()]):
d[i[0]] += float(i[1])
{'Brandon': 115.5,
'Patrick': 18.9,
'Sarah': 827.43,
'Jack': 45.0,
'James': 128.87}
from collections import defaultdict
def isfloat(value):
try:
float(value)
return True
except ValueError:
return False
username = ['Brandon', 'Patrick', 'Brandon', 'Jack', '', 'Sarah', 'Jack', 'Brandon', 'James', 'James', 'Sarah', '', 'Brandon']
account = ['5', '18.9', 'xyz', '', '', '825', '45', '10', '3.25', '125.62', '2.43', '', '100.5']
result = {}
for u, a in zip(username, account):
if isfloat(a):
if u not in result.keys():
result[u] = float(a)
else:
result[u] += float(a)
This will help, try part will automatically skip any non-digit values
username = ['Brandon', 'Patrick', 'Brandon', 'Jack', '', 'Sarah', 'Jack', 'Brandon', 'James', 'James', 'Sarah', '', 'Brandon']
account = ['5', '18.9', 'xyz', '', '', '825', '45', '10', '3.25', '125.62', '2.43', '', '100.5']
new_dict = {}
for key, value in zip(username, account):
try:
new_dict[key]=new_dict.get(key, 0.0) + float(value)
except:
pass
print(new_dict)
I have a nested dict with list of dicts as well, and some of my keys have special chars. What is the best way to remove those special chars from the keys.
The below that I have attempted works on dicts of dicts, but how can i extend it to take care of list of dicts as well.
>>> a={"#pipeline": "start", "#args": "-vv", "#start": "1598331637", "#info": {"#pipeline_stage": "tasks","#taskbegin": [{"#task": "1", "#time": "1598331638"}, {"#task": "2", "#time": "1598331638"}, {"#task": "3", "#time": "1598331638"}]}}
>>> a
{'#pipeline': 'start', '#args': '-vv', '#start': '1598331637', '#info': {'#pipeline_stage': 'tasks', '#taskbegin': [{'#task': '1', '#time': '1598331638'}, {'#task': '2', '#time': '1598331638'}, {'#task': '3', '#time': '1598331638'}]}}
>>> def _clean_keys(d):
... return {''.join(filter(str.isalnum, k)): _clean_keys(v) for k, v in d.items()} if isinstance(d, dict) else d
...
>>> _clean_keys(a)
{'pipeline': 'start', 'args': '-vv', 'start': '1598331637', 'info': {'pipelinestage': 'tasks', 'taskbegin': [{'#task': '1', '#time': '1598331638'}, {'#task': '2', '#time': '1598331638'}, {'#task': '3', '#time': '1598331638'}]}}
>>>
As you can see, the taskbegin list is not cleaned.
Using recursion
Ex:
a={"#pipeline": "start", "#args": "-vv", "#start": "1598331637", "#info": {"#pipeline_stage": "tasks","#taskbegin": [{"#task": "1", "#time": "1598331638"}, {"#task": "2", "#time": "1598331638"}, {"#task": "3", "#time": "1598331638"}]}}
def _clean_keys(d):
res = {}
if isinstance(d, dict):
for k, v in d.items():
k = ''.join(filter(str.isalnum, k))
if isinstance(v, list): #Check if type of value is list
res[k] = [_clean_keys(i) for i in v] #use recursion
else:
res[k]= _clean_keys(v)
else:
res = d
return res
print(_clean_keys(a))
Output:
{'args': '-vv',
'info': {'pipelinestage': 'tasks',
'taskbegin': [{'task': '1', 'time': '1598331638'},
{'task': '2', 'time': '1598331638'},
{'task': '3', 'time': '1598331638'}]},
'pipeline': 'start',
'start': '1598331637'}
Try this, works fine
Code
def clean_dict(val):
if type(val) == list:
return clean_list(val)
if type(val) == dict:
return {clean(k) : clean_dict(v) for k, v in val.items()}
return val
def clean_list(val):
return [clean_dict(v) for v in val]
def clean(val):
''.join([c for c in val if c.isalnum()])
Output
a={"#pipeline": "start", "#args": "-vv", "#start": "1598331637", "#info": {"#pipeline_stage": "tasks","#taskbe
gin": [{"#task": "1", "#time": "1598331638"}, {"#task": "2", "#time": "1598331638"}, {"#task": "3", "#time": "1
598331638"}]}}
clean_dict(a)
Out[8]:
{'pipeline': 'start',
'args': '-vv',
'start': '1598331637',
'info': {'pipelinestage': 'tasks',
'taskbegin': [{'task': '1', 'time': '1598331638'},
{'task': '2', 'time': '1598331638'},
{'task': '3', 'time': '1598331638'}]}}
I am trying to create a list structure in a loop:
[children:[{text: "Title 1", id: '1', expanded: true,children: [{text: "title2", leaf: true ,},{text: "title3", leaf: true}]},{text: "Title4", id: '4', expanded: true, children: [{text: "title5", leaf: true,} ]}]]
The source data looks like this:
mylist =[{'id': '1', 'name': 'Title1', 'id_parent': '0'}, {'id': '2', 'name': 'title2', 'id_parent': '1'}, {'id': '3', 'name': 'title3', 'id_parent': '1'}, {'id': '4', 'name': 'Title4', 'id_parent': '0'}, {'id': '5', 'name': 'title5', 'id_parent': '4'}]
Using recursion, I go through the data and get parental and childish records:
def get_parent(id_parent):
c = []
for x in mylist:
if not x["id"] == id_parent and x["id_parent"] == id_parent:
if x["id_parent"] == id_parent:
x['expanded'] = True
else:
x['leaf'] = True
c.append(x)
return(c)
def get_tree(t):
lst = []
main_data = []
for x in get_parent(t):
all_stor = {}
all_stor["text"] = x['name']
all_stor["id"] = x['id']
if x.get('expanded'):
all_stor["expanded"] = x['expanded']
else:
all_stor["leaf"] = x['leaf']
main_data.append(all_stor)
lst.append([main_data, get_tree(x["id"])])
return lst
main = get_tree("0")
print(main)
How to fill the main_data list in a loop in order to get the necessary structure?
Your expected output should be a list of children from the root level:
def get_tree(l, parent='0'):
children = []
for d in l:
if d['id_parent'] == parent:
details = {'text': d['name'], 'id': d['id']}
grand_children = get_tree(l, d['id'])
if grand_children:
details.update({'expanded': True, 'children': grand_children})
else:
details['leaf'] = True
children.append(details)
return children
so that with your sample input, get_tree(mylist) would return:
[{'text': 'Title1', 'id': '1', 'expanded': True, 'children': [{'text': 'title2', 'id': '2', 'leaf': True}, {'text': 'title3', 'id': '3', 'leaf': True}]}, {'text': 'Title4', 'id': '4', 'expanded': True, 'children': [{'text': 'title5', 'id': '5', 'leaf': True}]}