Recursion always updates the dictionary - python

def recursion(input_type):
print('input_type ',input_type)
if isinstance(input_type, dict):
num = 0
for k,v in input_type.items():
if isinstance(v, dict):
print('from recursion')
recursion(v)
elif isinstance(v, list):
for j in v:
if isinstance(j, dict):
print('from recursion level 2')
recursion(j)
else:
temp_dict = {k:v}
print('type: ',type(temp_dict), k, v)
print('num',num)
num = num+1
for i in list_:
recursion(i)
How to get the interim results from the recursion.
consider the input as shown below:
input: [{'a':a, 'b':b, 'c':[{'d':d, 'e':e}]}]
Updated input: [ {'a':a, 'b':b, 'c': { 'd':d, 'e': [ {'f':f, 'g':g}, {'f':f1, 'g':g1} ] } } ]
desired output: [{'a':a, 'b':b, 'd':d, 'f':f, 'g':g, 'f_new':f1, 'g_new':g1}]
If the key is duplicate then it should update such as 'f' to 'f_new' or something like that
Thank you in advance!!

You can iterate over the dict items and if an item is a list, recursively flatten the dicts within it:
def f(o):
return {a: b for k, v in o.items() for a, b in ((i for d in (v if isinstance(v, list)
else (v,)) for i in f(d).items()) if isinstance(v, (list, dict)) else ((k, v),))}
so that given:
lst = [{'a': 'a', 'b': 'b', 'c': [{'d': 'd', 'e': 'e'}, {'f': [{'g': 'g'}]}]}]
[f(d) for d in lst] would return:
[{'a': 'a', 'b': 'b', 'd': 'd', 'e': 'e', 'g': 'g'}]
and that given:
lst = [{'a': 'a', 'b': 'b', 'c': {'d': 'd', 'e': {'f': 'f', 'g': 'g'}}}]
[f(d) for d in lst] would return:
[{'a': 'a', 'b': 'b', 'd': 'd', 'f': 'f', 'g': 'g'}]
To avoid collisions in merged keys, append _new to a duplicating key until it is found not pre-existing, in which case you cannot use comprehension:
def f(o):
output = {}
for k, v in o.items():
for a, b in ((i for d in (v if isinstance(v, list) else (v,)) for i in f(d).items())
if isinstance(v, (list, dict)) else ((k, v),)):
while a in output:
a += '_new'
output[a] = b
return output
so that given:
lst = [{'a': 'a', 'b': 'b', 'c': {'d': 'd', 'e': [{'f': 'f', 'g': 'g'}, {'f': 'f1', 'g': 'g1'}]}}]
[f(d) for d in lst] would return:
[{'a': 'a', 'b': 'b', 'd': 'd', 'f': 'f', 'g': 'g', 'f_new': 'f1', 'g_new': 'g1'}]
Demo: https://repl.it/#blhsing/NonstopSeveralActionscript

Related

How to match two lists and insert into specific value?

I have two lists
a = ['b','c','a','d','v']
g = [{'c':'1'},{'c':'2'},{'c':'3'},{'d':'1'},{'d':'2'}]
I want to match the key in the dictionary in the list g to the elements in list a, if they are matched, the elements in list g will be inserted into list a.
The desired outcome is:
['b','c',{'c':'1'},{'c':'2'},{'c':'3'},'a','d',{'d':'1'},{'d':'2'},'v']
Try:
a = ["b", "c", "a", "d", "v"]
g = [{"c": "1"}, {"c": "2"}, {"c": "3"}, {"d": "1"}, {"d": "2"}]
tmp = {}
for d in g:
for k in d:
tmp.setdefault(k, []).append(d)
out = []
for v in a:
out.append(v)
out.extend(tmp.get(v, []))
print(out)
Prints:
['b', 'c', {'c': '1'}, {'c': '2'}, {'c': '3'}, 'a', 'd', {'d': '1'}, {'d': '2'}, 'v']
Try using sorted:
print(sorted(a + g, key=lambda x: list(x)[0]))
Output:
['a', 'b', 'c', {'c': '1'}, {'c': '2'}, {'c': '3'}, 'd', {'d': '1'}, {'d': '2'}, 'e']
a = ['a','b','c','d','e']
g = [{'c':'1'},{'c':'2'},{'c':'3'},{'d':'1'},{'d':'2'},{'z':'1'}]
for dic in g:
for key in dic:
if key in a:
a.append(dic)
print(a)
#output ['a', 'b', 'c', 'd', 'e', {'c': '1'}, {'c': '2'}, {'c': '3'}, {'d': '1'}, {'d': '2'}]
After this, you can do sorting using lambda if required.

Comparing 2 lists of dictionaries and adding a key,value when a common key is identified

I have two lists of dictionaries. The first list will contain significantly more dictionaries than the second list. There could be up to 200-300 dictionaries in list1 and no more than 10-15 dictionaries in list2.
For example, any dictionary in list1 that has the same 'g': h key/value as that of list2 needs to add key/value 'j': k to list 1.
list1 = [{'a': b, 'c': d, 'e': f, 'g': h},
{'a': b, 'c': d, 'e': f, 'g': h},
{'a': b, 'c': d, 'e': f, 'g': h},
{'a': b, 'c': d, 'e': f, 'g': h}
]
list2 = [{'g': h, 'j': k}]
I'm struggling on finding any previous examples of this type and cannot figure out a function of my own.
A trivial implementation could be:
for d1 in list1:
for d2 in list2:
if any(pair in d1.items() for pair in d2.items()):
d1.update(d2)
The value of list1 after this transformation:
[{'a': 'b', 'c': 'd', 'e': 'f', 'g': 'h', 'j': 'k'},
{'a': 'b', 'c': 'd', 'e': 'f', 'g': 'h', 'j': 'k'},
{'a': 'b', 'c': 'd', 'e': 'f', 'g': 'h', 'j': 'k'},
{'a': 'b', 'c': 'd', 'e': 'f', 'g': 'h', 'j': 'k'}]

Constructing a nested dictionary based on parent-children relationship?

I am given a list of dictionaries like this:
[
{'A': ['B', 'C', 'D']},
{'B': ['E', 'F']},
{'C': ['E']},
{'F': ['G', 'H']}
]
A key in the dictionary is a parent of a corresponding dictionary value, i.e., {parent: [child1, child2, child3]}
How can I construct a tree-like dictionary in the following format like the following:
{'A':{'B':{'E': None,
'F': {'G': None,
'H': None}
},
'C': {'E': None}}
If a node doesn't have a child, we will fill its value with None. I don't know how to write a recursive process to transform the list into a dictionary, any idea?
Thanks!
You can do this with a recursive function:
def find_set(d, k, v):
for key, value in d.items():
if isinstance(value, dict):
find_set(d[key], k, v)
return
if key == k:
d[key] = {}
for i in v:
d[key][i] = None
return d
d[k] = {}
for i in v:
d[k][i] = None
return d
Code:
l = [{'A': ['B', 'C', 'D']}, {'B': ['E', 'F']}, {'C': ['E']}, {'F': ['G', 'H']}]
d = {}
for node in l:
for key, value in node.items():
find_set(d, key, value)
d will be :
{'A': {'B': {'E': None, 'F': {'G': None, 'H': None}, 'C': {'E': None}}, 'C': None, 'D': None}}
You can use recursion:
d = [{'A': ['B', 'C', 'D']}, {'B': ['E', 'F']}, {'C': ['E']}, {'F': ['G', 'H']}]
d1 = dict(list(i.items())[0] for i in d)
def flatten_structure(d, root = 'A'):
if root:
return {root:flatten_structure(d1[root], None)}
return {i:flatten_structure(d1[i], None) if i in d1 else None for i in d}
print(flatten_structure(d1['A']))
Output:
{'A': {'B': {'E': None, 'F': {'G': None, 'H': None}}, 'C': {'E': None}, 'D': None}}

Merging Key-Value Pairings in Dictionary

I have a dictionary that consists of employee-manager as key-value pairs:
{'a': 'b', 'b': 'd', 'c': 'd', 'd': 'f'}
I want to show the relations between employee-manager at all levels (employee's boss, his boss's boss, his boss's boss's boss etc.) using a dictionary. The desired output is:
{'a': [b,d,f], 'b': [d,f], 'c': [d,f], 'd': [f] }
Here is my attempt which only shows the first level:
for key, value in data.items():
if (value in data.keys()):
data[key] = [value]
data[key].append(data[value])
I can do another conditional statement to add the next level but this would be the wrong way to go about it. I'm not very familiar with dictionaries so what would be a better approach?
>>> D = {'a': 'b', 'b': 'd', 'c': 'd', 'd': 'f'}
>>> res = {}
>>> for k in D:
... res[k] = [j] = [D[k]]
... while j in D:
... j = D[j]
... res[k].append(j)
...
>>> res
{'b': ['d', 'f'], 'c': ['d', 'f'], 'd': ['f'], 'a': ['b', 'd', 'f']}
You may use the concept of recursion as :
def get_linked_list(element, hierarchy, lst):
if element:
lst.append(element)
return get_linked_list(hierarchy.get(element, ""), hierarchy, lst)
else:
return lst
And then access the hierarchy as:
>>> d = {'a': 'b', 'b': 'd', 'c': 'd', 'd': 'f'}
>>> print {elem:get_linked_list(elem, d, [])[1:] for elem in d.keys()}
>>> {'a': ['b', 'd', 'f'], 'c': ['d', 'f'], 'b': ['d', 'f'], 'd': ['f']}
However care must be taken as this may get to an infinite loop if we have an item in the dictionary as "a": "a"
x={'a': 'b', 'b': 'd', 'c': 'd', 'd': 'f'}
d={}
l=x.keys()
for i in l:
d.setdefault(i,[])
d[i].append(x[i])
for j in l[l.index(i)+1:]:
if j==d[i][-1]:
d[i].append(x[j])
print d
Output:{'a': ['b', 'd', 'f'], 'c': ['d', 'f'], 'b': ['d', 'f'], 'd': ['f']}

python reverse/transponse a dictionary [duplicate]

This question already has answers here:
Invert keys and values of the original dictionary
(3 answers)
Closed 8 years ago.
I am looking to tranpose a dictionary on python and after looking around i was not able to ifnd a solution for this. Does anybody know how could i reverse a dictionary like the following as input:
graph = {'A': ['B', 'C'],
'B': ['C', 'D'],
'C': ['D'],
'D': ['C'],
'E': ['F'],
'F': ['C']}
so that i get something like:
newgraph = {'A': [''],
'B': ['A'],
'C': ['A', 'B', 'D','F'],
'D': ['B', 'C'],
'E': [''],
'F': ['E']}
Use defaultdict:
newgraph = defaultdict(list)
for x, adj in graph.items():
for y in adj:
newgraph[y].append(x)
While it doesn't seem to make any sense to have the empty string '' in the empty lists, it's certainly possible:
for x in newgraph:
newgraph[x] = newgraph[x] or ['']
Use defaultdict:
>>> from collections import defaultdict
>>> graph = {'A': ['B', 'C'],
... 'B': ['C', 'D'],
... 'C': ['D'],
... 'D': ['C'],
... 'E': ['F'],
... 'F': ['C']}
>>> new_graph = defaultdict(list)
>>> for ele in graph.keys():
... new_graph[ele] = []
...
>>> for k, v in graph.items():
... for ele in v:
... new_graph[ele].append(k)
...
>>> pprint(new_graph)
{'A': [],
'B': ['A'],
'C': ['A', 'B', 'D', 'F'],
'D': ['B', 'C'],
'E': [],
'F': ['E']}
It's also possible without defaultdict.
Here I've left the empty keys in the new dict with the value None.
graph = {'A': ['B', 'C'],
'B': ['C', 'D'],
'C': ['D'],
'D': ['C'],
'E': ['F'],
'F': ['C']}
g = dict.fromkeys(graph.keys())
for k, v in graph.iteritems():
for x in v:
if g[x]: g[x] += [k]
else: g[x] = [k]
for k in sorted(graph.keys()):
print k, ':', g[k]
Output:
A : None
B : ['A']
C : ['A', 'B', 'D', 'F']
D : ['C', 'B']
E : None
F : ['E']

Categories

Resources