Nested Dicts in Python keys and values - python

I got a dict of dicts which looks like this:
d {
1: {
a: 'aaa',
b: 'bbb',
c: 'ccc'
}
2: {
d: 'dddd',
a: 'abc',
c: 'cca'
}
3: {
e: 'eee',
a: 'ababa',
b: 'bebebe'
}
}
I want to convert by dict like this
d {
a: 1,2,3
b: 1,3
c: 1,2
d: 2
e: 3
}
How can I achieve this?I tried reversing it but it throws unhashable dict.

a = {
1: {
"a": "aaa",
"b": "bbb",
"c": "ccc"
},
2: {
"d": "ddd",
"a": "abc",
"c": "cca"
},
3: {
"e": "eee",
"a": "ababa",
"b": "bebebe"
}
}
from collections import defaultdict
b = defaultdict(list)
for i, v in a.items():
for j in v:
b[j].append(i)
The result b is:
defaultdict(<class 'list'>, {'a': [1, 2, 3], 'b': [1, 3], 'c': [1, 2], 'd': [2], 'e': [3]})

You just need to figure out the logic for it. Iterate through the main dictionary, and use the keys of the sub dictionaries to build your new dict.
d = {
1: {
'a': 'aaa',
'b': 'bbb',
'c': 'ccc'
},
2: {
'd': 'dddd',
'a': 'abc',
'c': 'cca'
},
3: {
'e': 'eee',
'a': 'ababa',
'b': 'bebebe'
}
}
newdict = {}
for k,v in d.items():
for keys in v:
newdict.setdefault(keys,[]).append(k)
print(newdict)

Related

GroupBy results to list of dictionaries, Using the grouped by object in it

My DataFrame looks like so:
Date Column1 Column2
1.1 A 1
1.1 B 3
1.1 C 4
2.1 A 2
2.1 B 3
2.1 C 5
3.1 A 1
3.1 B 2
3.1 C 2
And I'm looking to group it by Date and extract that data to a list of dictionaries so it appears like this:
[
{
"Date": "1.1",
"A": 1,
"B": 3,
"C": 4
},
{
"Date": "2.1",
"A": 2,
"B": 3,
"C": 5
},
{
"Date": "3.1",
"A": 1,
"B": 2,
"C": 2
}
]
This is my code so far:
df.groupby('Date')['Column1', 'Column2'].apply(lambda g: {k, v for k, v in g.values}).to_list()
Using this method can't use my grouped by objects in the apply method itself:
[
{
"A": 1,
"B": 3,
"C": 4
},
{
"A": 2,
"B": 3,
"C": 5
},
{
"A": 1,
"B": 2,
"C": 2
}
]
Using to_dict() giving me the option to reach the grouped by object, but not to parse it to the way I need.
Anyone familiar with some elegant way to solve it?
Thanks!!
You could first reshape your data using df.pivot, reset the index, and then apply to_dict to the new shape with the orient parameter set to "records". So:
import pandas as pd
data = {'Date': ['1.1', '1.1', '1.1', '2.1', '2.1', '2.1', '3.1', '3.1', '3.1'],
'Column1': ['A', 'B', 'C', 'A', 'B', 'C', 'A', 'B', 'C'],
'Column2': [1, 3, 4, 2, 3, 5, 1, 2, 2]}
df = pd.DataFrame(data)
df_pivot = df.pivot(index='Date',columns='Column1',values='Column2')\
.reset_index(drop=False)
result = df_pivot.to_dict('records')
target = [{'Date': '1.1', 'A': 1, 'B': 3, 'C': 4},
{'Date': '2.1', 'A': 2, 'B': 3, 'C': 5},
{'Date': '3.1', 'A': 1, 'B': 2, 'C': 2}]
print(result == target)
# True

How to merge two dict together while maintaining same structure but combining values?

Say I have 2 dict with same structure (this entire dict is the structure for any one of the dicts):
{
'0': {
'A': a,
'B': b,
},
'1': {
'C': c,
'D': d,
}
}
#Sample input and output:
#dict1
{
'0': {
'A': 0,
'B': 1,
},
'1': {
'C': 2,
'D': 3,
}
}
#dict2
{
'0': {
'A': 5,
'B': 5,
},
'1': {
'C': 5,
'D': 5,
},
'3': { 'E': 5 } #this will be ignored when combining
}
#merged output with addition:
{
'0': {
'A': 5,
'B': 6,
},
'1': {
'C': 7,
'D': 8,
}
}
Ideally, everything about both dicts are the same except for the values a,b,c,d. For any subsequent dicts that have parts in their structure that are different from the first dict, those parts are ignored when merging. Like how the 3 AND E key in dict2 was ignored in the merge.
How can I combine both dicts into one dict that maintains the same structure, but with merged values? I would like to make this generic, so this 'merge' operation could be addition, subtraction, etc. And the number of dicts to merge can also change (not just 2 at a time).
Thanks, I hope to learn more about Python from your solutions
is you want that type of code
marged={}
for i in a:
for j in a[i]:
marged.setdefault(j,a[i].get(j))
print(marged)
Output:
{'A': 'a', 'B': 'b', 'K': 'k', 'L': 'l', 'C': 'c', 'D': 'd'}
Input:
a={
'0': {
'A': "a",
'B': "b",
'K':"k",
'L':"l"
},
'1': {
'C': "c",
'D': "d"
}
}
You can simply use UPDATE method.
if a is a dictionary and you want to add another dictionary say b.
then simply use
a.update(b)
This is to combine all the dicts, i.e, to merge.
d = {
'0': {
'A': a,
'B': b,
},
'1': {
'C': c,
'D': d,
},
}
def merge(d):
merged_dict = {}
for k in d:
for key in d[k]:
if not merged_dict.get(key, False):
merged_dict[key] = d[k][key]
return merged_dict
md = merge(d)
This should just merge the different dicts into one.
For supporting arbitrary dict structure and nesting, you will have to use a recursive function. Pass the operator as a parameter and use e.g. reduce to calculate the value for all the passed dicts (one or more). This assumes only dicts of dicts, but could also handle e.g. lists with another block if isinstance(first, list) and a corresponding list comprehension.
import functools, operator
def merge(op, first, *more):
if isinstance(first, dict):
return {key: merge(op, first[key], *(d[key] for d in more if key in d))
for key in first}for key in first}
else:
return functools.reduce(op, more, first)
A = {'0': {'A': 1, 'B': 2}, '1': {'C': 3, 'D': 4}}
B = {'0': {'A': 5, 'B': 6}, '1': {'C': 7, 'D': 8}}
print(merge(operator.add, A, B))
# {'0': {'A': 6, 'B': 8}, '1': {'C': 10, 'D': 12}}
Also works with more than two dicts, different operator, or if the more dicts have more or fewer keys than first:
C = {'0': {'A': 9, 'B': 10}, '1': {'C': 11, 'D': 12}}
D = {'0': {'A': 13, 'X': 14}, '2': {'C': 15, 'D': 16}}
print(merge(lambda x, y: f"{x}-{y}", A, B, C, D))
# {'0': {'A': '1-5-9-13', 'B': '2-6-10'}, '1': {'C': '3-7-11', 'D': '4-8-12'}}
It still assumes that values corresponding to the same keys in first and more have the same type, though.

python nested dict convert from regular json to nest

I am stuck on convert jsons from regular (key-value) to nested.
for example:
j = { 'a': 5,
'b': 3,
'c.c1': 2,
'c.c2':5,
'd.dd.d1': 0,
'd.dd.d2':9
}
and I need to get:
new_j = {
'a': 5,
'b': 3,
'c':
{'c1': 2,
'c2':5}
'd':
{'dd' :
{'d1': 0,
'd2': 9}
},
}
there are easy method to do this?
How about this?
j_new = {}
for key,value in j.items():
keys = key.split('.')
level = j_new
for key in keys[:-1]:
if key not in level:
level[key]={}
level = level[key]
level[keys[-1]]=value
print(j_new)
Which returns:
{'a': 5, 'b': 3, 'c': {'c1': 2, 'c2': 5}, 'd': {'dd': {'d1': 0, 'd2': 9}}}
Try this:
d = {}
def setValue(dic, keys, value):
for key in keys[:-1]:
dic = dic.setdefault(key, {})
dic[keys[-1]] = value
for k,v in j.items():
setValue(d, k.split('.'), v)
Output:
{
"a": 5,
"c": {
"c2": 5,
"c1": 2
},
"b": 3,
"d": {
"dd": {
"d2": 9,
"d1": 0
}
}
}

Add one property to json in python

I have the below json, I want to add one more property:
[ {
"A": 1,
"B": "str"
},
{
"A": 2,
"B": "str2"
},
{
"A": 3,
"B": "str3"
}
]
So I want something like this:
[ {
"A": 1,
"B": "str",
"C": "X"
},
{
"A": 2,
"B": "str2",
"C": "X"
},
{
"A": 3,
"B": "str3",
"C": "X"
}
]
What is the best way to do this?
Loop through each dict obj in the list and add required key value pair that you want:
List Before
list1 = [
{
"A": 1,
"B": "str"
},
{
"A": 2,
"B": "str2"
},
{
"A": 3,
"B": "str3"
}
]
The code
for l in list1:
l['C'] = 'X'
print(list1)
List After i.e Output
[{'A': 1, 'B': 'str', 'C': 'X'}, {'A': 2, 'B': 'str2', 'C': 'X'}, {'A': 3, 'B': 'str3', 'C': 'X'}]
>>> j = [ { "A": 1, "B": "str" }, { "A": 2, "B": "str2" }, { "A": 3, "B": "str3" } ]
>>> [i.update({'C': 'X'}) for i in j]
>>> j
[{'A': 1, 'B': 'str', 'C': 'X'}, {'A': 2, 'B': 'str2', 'C': 'X'}, {'A': 3, 'B': 'str3', 'C': 'X'}]
Or, as per coldspeed's comment:
>>> for item in j:
... item['C'] = 'X'
...
>>> j
[{'A': 1, 'B': 'str', 'C': 'X'}, {'A': 2, 'B': 'str2', 'C': 'X'}, {'A': 3, 'B': 'str3', 'C': 'X'}]

How to update a key in a dictionary without overwriting the old value

input = { "a" : { "x": 1, "y": 2 },
"b" : { "x": 3, "z": 4 } }
output = {'y': {'a': 2},
'x': {'a': 1, 'b': 3},
'z': {'b': 4} }
I need to make a new dictionary given the input and it should come out as the output. So far I have written:
def pivot_nested_dict(nested_dict):
5 stateDict={}
6 for i in nested_dict:
7 dict2=nested_dict[i]
8 for j in dict2:
9 stateDict[j]= {i: dict2[j]}
10 return stateDict
11
12 print pivot_nested_dict(input)
I almost have the answer, output={'y': {'a': 2}, 'x': {'b': 3}, 'z': {'b': 4}}.
So, the x key is overwriting the 'a': 1. How do I keep both the a and the b?
What you need to this is check if the key is already in stateDict, if it is, then add a new element to the nested dictionary:
def pivot_nested_dict(nested_dict):
stateDict = {}
for i in nested_dict:
dict2 = nested_dict[i]
for j in dict2:
if j not in stateDict:
stateDict[j] = {i: dict2[j]}
else:
stateDict[j][i] = dict2[j]
return stateDict
print pivot_nested_dict(inp)
Short of duplicating the dictionary, there is no way to retain the original value on a dictionary once you change the value that corresponds to the given key.
For example, the below overwriting will always happen no matter how complex the data structure.
x = {'a':1}
x['a'] = 2
print x
>>> {'a': 2}
You can duplicate it, but the original value will need to be managed manually.
x = {'a':1}
x,oldx = x,x.copy()
oldx['a'] = 2
print x, oldx
>>> {'a': 2} {'a': 1}
You could take advantage of the fact that values can be any type of structure including arrays or dictionaries, to store each successive change of value.
I ve got this little script yo get your job done.
NOTE: Provided the input is correct.
code:
output = {}
for d in input.items():
for item in d:
if type(item) == dict:
for i in item.keys():
d = {k:item[i]}
output[i] = {k:item[i]} if not i in output.keys() else dict(output[i].items() + d.items())
else: k=item
input:
input = { "a" : { "x": 1, "y": 2 ,'z':15},"b" : { "x": 3, "z": 4 } }
output:
{'y': {'a': 2}, 'x': {'a': 1, 'b': 3}, 'z': {'a': 15, 'b': 4}}
Hope this helps :)
I have this one
input = { "a" : { "x": 1, "y": 2 },
"b" : { "x": 3, "z": 4 } }
output = {}
for k,v in zip(input.keys(), input.values()):
for kk, vv in zip(v.keys(), v.values()):
if kk in output.keys():
output[kk][k] = vv
else:
output[kk] = {k : vv}

Categories

Resources