how to convert data into nested dictionary in python,dataframe - python

I have a large dataset of item code and component each item code correlate with component and further component become item code of another component. how can I make a nested dictionary in python
item code component
a q
b w
c r
d t
e y
q u
q v
desired output:-
{a:{q:[u,v]},b:w,c:r etc}
How can I achieve this nested dictionary in python, I have large data
I used defaultdict but it gave me only a dictionary not a nested dictionary

In [108]: df = pd.DataFrame({'item_code': list('abcdeqq'), 'component': list('qwrtyuv')})
In [109]: import networkx as nx
In [110]: g = nx.DiGraph([(k,v) for k,v in zip(df['item_code'], df['component'])])
In [111]: {k:v if len(v) > 1 else v[0] for k,v in nx.convert.to_dict_of_lists(g).items() if v}
Out[111]: {'a': 'q', 'q': ['u', 'v'], 'b': 'w', 'c': 'r', 'd': 't', 'e': 'y'}

Using networkx you can get something like this. Based on this answer I am able to reach to this solution:
import networkx
G = nx.DiGraph()
G.add_edges_from(df.values)
def comb_tup(li_tup):
d = {}
crnt = d # memo the crnt subtree
stck = [] # stack of (sub)trees along current path
for k, v in li_tup:
while stck and k not in crnt:
crnt = stck.pop()
if k not in crnt:
crnt[k] = {}
stck.append(crnt)
crnt = crnt[k]
crnt[v] = {}
return d
final_di = {}
for node in G.nodes:
vi = list(nx.dfs_edges(G,node))
d = comb_tup(vi)
if len(d.keys()):
for k,v in d.items():
final_di[k] = v
final_di:
{'a': {'q': {'u': {}, 'v': {}}},
'q': {'u': {}, 'v': {}},
'b': {'w': {}},
'c': {'r': {}},
'd': {'t': {}},
'e': {'y': {}}}
If you have this data:
item_code component
0 a q
1 b w
2 c r
3 d t
4 e y
5 q u
6 q v
7 u x
final_di:
{'a': {'q': {'u': {'x': {}}, 'v': {}}},
'q': {'u': {'x': {}}, 'v': {}},
'b': {'w': {}},
'c': {'r': {}},
'd': {'t': {}},
'e': {'y': {}},
'u': {'x': {}}}

Related

Reduce levels of nested dictionaries when they have one element

I need to reduce the nested levels of a dictionary when a node has 1 element, by appending the inner key to the upper key.
Example:
Given this dictionary:
{'A': {'a': {'1': {}}},
'B': {'b': {'2': {}},
'c': {'3': {'x': {}}},
'd': {},
'e': {'0': {},
'1': {},
},
},
}
I need to return:
{'A a 1': {},
'B': {'b 2': {},
'c 3 x': {},
'd': {},
'e': {'0': {},
'1': {},
},
},
}
It should be generic for any number of levels, and the last element is always an empty dict.
You can first flatten the structure to retrieve all paths and then rebuild it using collections.defaultdict:
import collections
data = {'A': {'a': {'1': {}}}, 'B': {'b': {'2': {}}, 'c': {'3': {'x': {}}}, 'd': {}, 'e': {'0': {}, '1': {}}}}
def flatten(d, c = []):
for a, b in d.items():
if not b:
yield (c+[a], b)
else:
yield from flatten(b, c +[a])
def compress(d):
_d, r = collections.defaultdict(list), {}
for [a, *b], c in d:
_d[a].append((b, c))
for a, b in _d.items():
val = compress(b) if len(b) > 1 and all(j for j, _ in b) else b[0][-1]
r[a if len(b) > 1 else a+' '+' '.join(b[0][0])] = val
return r
print(compress(list(flatten(data))))
Output:
{'A a 1': {},
'B': {'b 2': {},
'c 3 x': {},
'd ': {},
'e': {'0 ': {},
'1 ': {}}
}
}
I believe this recursive function works for your example:
def flatten_keys(key_so_far = '', d={}):
if len(d) > 1:
sub_dict = {}
for (k,v) in d.items():
sub_dict.update(flatten_keys(k, v))
return {key_so_far: sub_dict} if key_so_far else sub_dict
elif d == {}:
return {key_so_far: {}}
else:
k,v = list(d.items())[0]
key_so_far += (' ' if key_so_far else '') + k
return(flatten_keys(key_so_far, v))
input_d = {'A': {'a': {'1': {}}},
'B': {'b': {'2': {}},
'c': {'3': {'x': {}}},
'd': {},
'e': {'0': {},
'1': {},
},
},
}
flatten_keys(input_d)
# {'A a 1': {}, 'B': {'b 2': {}, 'c 3 x': {}, 'd': {}, 'e': {'0': {}, '1': {}}}}

python update nested dictionary with other nested dictionary [duplicate]

This question already has answers here:
How to update values in nested dictionary if keys are in a list? [duplicate]
(5 answers)
Closed 3 years ago.
I want to use dd1 and dd2 to update dd3
dd1 = {'a': {'b': [{'x':1}]}}
dd2 = {'a': {'c': [{'x':2}]}}
dd3 = {'a': {'b': {}, 'c': {}}}
so I get dd3:
dd3 = {'a': {'b': [{'x':1}], 'c': [{'x':2}]}}
I know how to update flat dictionary
d1 = {'a': 1, 'b': 2, 'c': 3}
d2 = {'a': 2, 'b': 3, 'd': 4}
d3 = defaultdict(list)
for k, v in chain(d1.items(), d2.items()):
d3[k].append(v)
but struggle to find clear way to update nested dictionary:
With recursive traversal (assuming that all source dicts have same depth levels and lists as final expected update values):
dd1 = {'a': {'b': [{'x':1}]}}
dd2 = {'a': {'c': [{'x':2}]}}
dd3 = {'a': {'b': {}, 'c': {}}}
def update_nested_dict(target, d1, d2):
for k,v in target.items():
d1_v, d2_v = d1.get(k, []), d2.get(k, [])
if isinstance(v, dict):
if not v:
target[k] = d1_v + d2_v
else:
update_nested_dict(v, d1_v, d2_v)
update_nested_dict(dd3, dd1, dd2)
print(dd3)
The output:
{'a': {'b': [{'x': 1}], 'c': [{'x': 2}]}}
You can use recursion:
dd1 = {'a': {'b': [{'x':1}]}}
dd2 = {'a': {'c': [{'x':2}]}}
dd3 = {'a': {'b': {}, 'c': {}}}
def update(d, *args):
return {a:(lambda x:x[0] if not b else update(b, *x))([i[a] for i in args if a in i])\
if isinstance(b, dict) else b for a, b in d.items()}
print(update(dd3, dd1, dd2))
Output:
{'a': {'b': [{'x': 1}], 'c': [{'x': 2}]}}
This solution can handle multiple dictionaries of varying depths:
dd1 = {'a': {'b':{'d':{'e':[{'x':1}]}}}}
dd2 = {'a': {'c': [{'x':2}]}}
dd4 = {'a':{'j':{'k':[{'x':3}]}}}
dd3 = {'a': {'b': {'d':{'e':{}}}, 'c': {}, 'j':{'k':{}}}}
print(update(dd3, dd1, dd2, dd4))
Output:
{'a': {'b': {'d': {'e': [{'x': 1}]}}, 'c': [{'x': 2}], 'j': {'k': [{'x': 3}]}}}

How to create nested dictionary without losing data?

I have the file which contains distance values for a set of nodes in matrix form. I extracted those values and want to save them in a nested dictionary.
I already tried, but my dictionary contains only values from the last iteration.
d={}
i, j = 0,0
for f in tmp:
for k in range(3,len(f),3):
d[nodes[i]] = {}
d[nodes[i]][nodes[j]]= f[k-2]+f[k-1]
j += 1
i += 1
j = 0
return d
d={'A': {'P': '5'},
'B': {'P': '3'},
'C': {'P': '6'},
'D': {'P': '5'},
'E': {'P': '3'},
'F': {'P': '33'},
'G': {'P': '21'},
'H': {'P': '39'},
'I': {'P': '4'}}
But d should contain:
d={"A":{"A":5,"B":6, "C":7, "D":8, "E":9, "F":10, "G":11;"H":12, "I":13},
"B":{"A":3,"B":4, "C":5, "D":8, "E":9, "F":14, "G":11;"H":12,
"I":16}},.....
You're re-initializing the second-level dict each iteration of your inner loop. That is what is causing it to "lose data".
Instead, you could use a defaultdict:
from collections import defaultdict
d = defaultdict(dict)
i, j = 0,0
for f in tmp:
for k in range(3,len(f),3):
d[nodes[i]][nodes[j]]= f[k-2]+f[k-1]
j += 1
i += 1
j = 0
return d

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}}

Python How to Extract data from Nested Dict

I have output from python networkX code:
flow_value, flow_dict = nx.maximum_flow(T, 'O', 'T')
print(flow_dict)
#Output as followesenter
#{'O': {'A': 4, 'B': 6, 'C': 4}, 'A': {'B': 1, 'D': 3}, 'B': {'C': 0, 'E': 3,'D': 4}, 'C': {'E': 4}, 'E': {'D': 1, 'T': 6}, 'D': {'T': 8}, 'T': {}}
I want to extract all the data in the form looks like:
#('O','A',4),('O','B','6'),('O','C','4'),('A','B',1),......,('D','T',8)
Any ways can I traverse thru the nested dict and get the data I need?
I tried this and it works. Some type checking to only capture strings
def retrieve_all_strings_from_dict(nested_dict, keys_to_ignore = None):
values = []
if not keys_to_ignore:
keys_to_ignore = []
else: keys_to_ignore = to_list(keys_to_ignore)
if not isinstance(nested_dict,dict):
return values
dict_stack = []
dict_stack.append(nested_dict)
for dict_var in dict_stack:
data_list = [v for k,v in dict_var.items() if all([isinstance(v,str), k not in keys_to_ignore]) ]
additional_dicts = [v for k,v in dict_var.items() if isinstance(v,dict)]
for x in additional_dicts:
dict_stack.append(x)
for w in data_list:
values.append(w)
return values

Categories

Resources