adding value in nested dictionaries in python - python

I am trying to add value to inside dictionary.
aDict = { "id" :
{"name": None },
"id2" :
{"foo": None},
...
}
for k, v in aDict.items():
temp = [1,2,3,4]
aDict[k][v] = temp
then I got error, TypeError: unhashable type: 'dict'
How can I add value in nested dictionary?
---edit ---
My expected output is,
aDict = { "id" :
{"name": [1,2,3,4] },
"id2" :
{"foo": [1,2,3,4] },
...
}

When you do aDict[k], you already got the value which is dict and then you assign the temp to the specific key of the dict.
aDict = { 'id' :
{'name': None },
'id2':
{'foo':None}
}
for k, v in aDict.items():
temp = [1,2,3,4]
for keys in v.keys():
aDict[k][keys] = temp
Output
{'id': {'name': [1, 2, 3, 4]}, 'id2': {'foo': [1, 2, 3, 4]}}

For any arbitrary dictionary of dictionaries (no matter how deep it is), this works:
def go_deeper(aDict):
for k, v in aDict.items():
if v is None:
aDict[k] = temp
else:
go_deeper(v)
return aDict
Usage:
>>> temp = [1,2,3,4]
>>> go_deeper(aDict)
For example, for input:
aDict = { 'id' :
{'name': None },
"id2" :
{"foo":
{'bar': None }
}
}
the above code returns:
{'id': {'name': [1, 2, 3, 4]}, 'id2': {'foo': {'bar': [1, 2, 3, 4]}}}

Try this :
temp = [1,2,3,4]
for k in aDict:
for j in aDict[k]:
aDict[k][j]=temp
OUTPUT :
{'id': {'name': [1, 2, 3, 4]}, 'id2': {'foo': [1, 2, 3, 4]}}

You can get all keys by using d.keys() then add temp to this dictionary.
aDict = { "id" :
{"name": None },
"id2" :
{"foo": None},
"id3" :
{"bar": None, "boo": None},
}
temp = [1, 2, 3, 4]
for k, v in aDict.items():
for newKey in v.keys():
v[newKey] = temp
Result:
{'id': {'name': [1, 2, 3, 4]},
'id2': {'foo': [1, 2, 3, 4]},
'id3': {'bar': [1, 2, 3, 4], 'boo': [1, 2, 3, 4]}}

I would avoid the use of nested loops. And hence to get your desired output, I would do the following:
aDict = { "id" :
{"name": None },
"id2" :
{"foo": None}
}
for value in aDict.values():
temp = [1,2,3,4]
# obtain the key of inner dictionary
# this line could be written even better, if you're concerned about memory!
key = list(value.keys())[0]
# update the inner value
value[key] = temp
When I run this it gives your desired output
user#Kareems-MBP:Desktop$ python aDict.py
{'id': {'name': [1, 2, 3, 4]}, 'id2': {'foo': [1, 2, 3, 4]}}
Lastly, the TypeError you were getting TypeError: unhashable type: 'dict' is because you're trying to reference an item in the dictionary using a dictionary. Items in a dictionary can be referenced only using their keys. E.g. if we have the following dictionary:
myDict = {
'firstname': 'John',
'lastname': 'White'
}
and we want to reference the first item, we can do that only using myDict['firstname'], we cannot do that even with indices myDict[0]. You can imagine that you were doing something like this myDict[{'firstname': 'John'}].
I hope this has been helpful!

Related

how to sort a Dictionary in list? [duplicate]

This question already has answers here:
How do I sort a list of dictionaries by a value of the dictionary?
(20 answers)
Closed 2 months ago.
I had Question in python
Imagine a list with dictionaries in it
how can we sort it by a value in dictionary ?
Imagine this list :
lst = [
{
"a" : 3,
"b" : 2
},
{
"a" : 1,
"b" : 4
},
{
"a" : 2,
"b" : 3
}
]
how can we sort this list by value of "a" in each dictionary (python)
i mean i want this list at the end :
lst = [
{
"a" : 1,
"b" : 4
},
{
"a" : 2,
"b" : 3
},
{
"a" : 3,
"b" : 2
}
]
You could provide a lambda key to sorted:
>>> lst = [
... {
... "a" : 3,
... "b" : 2
... },
... {
... "a" : 1,
... "b" : 4
... },
... {
... "a" : 2,
... "b" : 3
... }
... ]
>>> sorted(lst, key=lambda d: d["a"])
[{'a': 1, 'b': 4}, {'a': 2, 'b': 3}, {'a': 3, 'b': 2}]
One approach, use the key argument with itemgetter:
from operator import itemgetter
lst = [{"a": 3, "b": 2}, {"a": 1, "b": 4}, {"a": 2, "b": 3}]
res = sorted(lst, key=itemgetter("a"))
print(res)
Output
[{'a': 1, 'b': 4}, {'a': 2, 'b': 3}, {'a': 3, 'b': 2}]
From the documentation on itemgetter:
Return a callable object that fetches item from its operand using the
operand’s getitem() method. If multiple items are specified,
returns a tuple of lookup values. For example:
After f = itemgetter(2), the call f(r) returns r[2].
After g =
itemgetter(2, 5, 3), the call g(r) returns (r[2], r[5], r[3]).

Flatten nested dictionary and overwrite values

I have a nested dictionary which I want to flatten while overwriting values of duplicate keys. Example input looks like this:
{
'abc': 1,
'foo': 2
'cba': {'abc': 3, 'baz': {
'foo': 4
}}
}
The goal is to overwrite values of keys in the top level dict with a value of the same key in a lower level dict, where the key in the lowest level dict is ruling.
and the output needs to be this:
{
'abc': 3,
'foo': 4,
'cba': {'abc': 3, 'baz': {
'foo': 4
}}
}
I was trying to find a solution on SO but couldn't find one... Hopefully someone can help me out :)
Not sure how robust this is, but I guess this is what you are looking for (credit to https://stackoverflow.com/a/6027615/5417511):
import collections
d = {
'abc': 1,
'foo': 2,
'cba': {'abc': 3, 'baz': {
'foo': 4
}}
}
def flatten(d):
items = []
for k, v in d.items():
if isinstance(v, collections.MutableMapping):
items.extend(flatten(v).items())
else:
items.append((k, v))
return dict(items)
d.update(flatten(d))
print(d)
{'abc': 3, 'foo': 4, 'cba': {'abc': 3, 'baz': {'foo': 4}}}
The code below finds the maximum depth value for each key and then recursively updates the original input:
from collections import defaultdict
data = {'abc': 1, 'foo': 2, 'cba': {'abc': 3, 'baz': {'foo': 4}}}
def levels(d, c = 0):
for a, b in d.items():
yield from [(c, a, b)] if not isinstance(b, dict) else levels(b, c+1)
l = defaultdict(dict)
for _l, a, b in levels(data):
l[a][_l] = b
def new_d(d):
return {a:new_d(b) if isinstance(b, dict) else l[a][max(l[a])] for a, b in d.items()}
result = new_d(data)
Output:
{'abc': 3, 'foo': 4, 'cba': {'abc': 3, 'baz': {'foo': 4}}}
you look probably for something like
ndir = {
'abc': 1,
'foo': 2,
'cba': {'abc': 3, 'baz': { 'foo': 4 }}
}
print(ndir)
res = {}
def GetContent(ndir):
for k, v in ndir.items():
if isinstance(v, dict):
GetContent(v)
else:
res[k]=v
GetContent(ndir)
print(res)

Create a dict from two lists of dicts with matching value

I have two lists of dictionaries, dict1 and dict2.
dict1 = [
{
'id': 0,
'name': 'James'
}, {
'id': 1,
'name': 'Bob'
}
]
dict2 = [
{
'id': 0,
'name': 'James'
}, {
'id': 1,
'name': 'James'
}, {
'id': 2,
'name': 'Bob'
}
]
And i want to create a dict like that:
result = {'James': [0, 1], 'Bob': [2]}
With the names from dict1 as keys and as value the list of "id" fields having the same name.
What's a clean way to do that in Python?
IIUC, I believe last line should be Bob and not James. That way, using pandas
import pandas as pd
>>> df1 = pd.DataFrame(dict1)
>>> df2 = pd.DataFrame(dict2)
>>> df2.groupby('name').agg(list).to_dict()['id']
{'Bob': [2], 'James': [0, 1]}
To filter only names that are in dict1,
>>> df2 = df2[df2['name'].isin(df1['name'])]
and group and agg after that
You can put the names in dict1 in a set first, so that when you iterate over dict2, you can check if the current name is in the set before adding it to the resulting dict of lists:
names = {d['name'] for d in dict1}
result = {}
for d in dict2:
if d['name'] in names:
result.setdefault(d['name'], []).append(d['id'])
result becomes:
{'James': [0, 1], 'Bob': [2]}
You can also do it in pure Python as following:
dict1 = [
{
'id': 0,
'name': 'James'
}, {
'id': 1,
'name': 'Bob'
}
]
dict2 = [
{
'id': 0,
'name': 'James'
}, {
'id': 1,
'name': 'James'
}, {
'id': 2,
'name': 'Bob'
}
]
names = [elem['name'] for elem in dict1]
result = dict((name,[]) for name in names)
for elem in dict2:
result[elem['name']].append(elem['id'])
print(result)
Output:
{'James': [0, 1], 'Bob': [2]}
IIUC, here's a defaultdict solution:
>>> from collections import defaultdict
>>>
>>> result = defaultdict(list)
>>> names = {d['name'] for d in dict1}
>>>
>>> for d in dict2:
...: name = d['name']
...: if name in names:
...: result[name].append(d['id'])
...:
>>> result
defaultdict(list, {'Bob': [2], 'James': [0, 1]})

How can I add multiple dict to one multiple?

I would like to have a dict like:
dict_a= {
'abc' : {'a':[1,2,3], 'b':[4,5,6], 'c':[7,8,9]},
'efg' : {'a':[10,11,12], 'b':[13,14,15], 'c':[16,17,18]},
'hij' : {'a':[21,22,23], 'b':[24,25,26], 'c':[27,28,29]}
}
so I separate into 2 dict
dict_b = {
'a': [],
'b': [],
'c': []
}
dict_a= {
'abc': {},
'efg': {},
'hij'
}
When I put data by using for loop, the last data will cover earlier data. The following is my code:
for x in sorted(dict_a):
for y in sorted(dict_b):
list= []
...
dict_b[y] = list
dict_a[x] = dict_b
and the result is:
dict_a= {
'abc' : {'a':[21,22,23], 'b':[24,25,26], 'c':[27,28,29]},
'efg' : {'a':[21,22,23], 'b':[24,25,26], 'c':[27,28,29]},
'hij' : {'a':[21,22,23], 'b':[24,25,26], 'c':[27,28,29]}
}
My expected result is:
dict_a= {
'abc' : {'a':[1,2,3], 'b':[4,5,6], 'c':[7,8,9]},
'efg' : {'a':[10,11,12], 'b':[13,14,15], 'c':[16,17,18]},
'hij' : {'a':[21,22,23], 'b':[24,25,26], 'c':[27,28,29]}
}
How can I solve it?
Update full code:
for market in sorted(MARKET_LUT):
for type in sorted(STOCK_TYPE_LUT):
try:
list = []
data = pd.read_csv(file_path, sep=' ', header=None, names=['code', 'name'])
list = data.code.tolist()
dict_b [type] = list
except Exception as e:
traceback.print_exc()
err = sys.exc_info()[1]
LOG_write_log(LOG_ERROR, str(err))
dict_a[x] = dict_b
Replace
for x in sorted(dict_a):
for y in sorted(dict_b):
list= []
...
dict_b[y] = list
dict_a[x] = dict_b
by
for x in sorted(dict_a):
new_dict = dict()
for y in sorted(dict_b):
list= []
...
new_dict[y] = list
dict_a[x] = new_dict
I can't get the exact result you want, but this seems close and illustrates how to avoid the problem you have about the last data covering earlier data.
from pprint import pprint
dict_b = {
'a': [],
'b': [],
'c': []
}
dict_a= {
'abc': {},
'efg': {},
'hij': {}
}
count = 1
for x in sorted(dict_a):
dict_temp = dict_b.copy() # Copy empty dict.
for y in sorted(dict_b):
lst = list(range(count, count+3))
dict_temp[y] = lst
count += 3
dict_a[x] = dict_temp
pprint(dict_a)
Result:
{'abc': {'a': [1, 2, 3], 'b': [4, 5, 6], 'c': [7, 8, 9]},
'efg': {'a': [10, 11, 12], 'b': [13, 14, 15], 'c': [16, 17, 18]},
'hij': {'a': [19, 20, 21], 'b': [22, 23, 24], 'c': [25, 26, 27]}}

How can i add the terms of one dict to another?

Let's assume i start with this dictionary:
mydict = {
'a': [[2,4], [5,6]],
'b': [[1,1], [1,7,9], [6,2,3]],
'c': [['a'], [4,5]],
}
How can i append values to 'a' yet be able to add a new key if i needed to let's say 'd' what i tried is
plus_min_dict = {}
plus_min_dict[key] = reference_dataset[key][line_number]
but it only gave one value per key apparently = destroyed the previous value, i want to update or append yet still be able to create a new key if it doesn't exist
Edit: To clarify let's assume this is my initial dictionary:
mydict = {
'a': [[2,4]],}
i do other calculations with another dictionary let's assume it's :
second_dict = {
'a': [ [5,6]],
'b': [[1,1], [1,7,9]],
'c': [['a'], [4,5]],
}
these calculations showed me that i have interest in [5,6] of 'a' and [1,7,9] of 'b' so i want mydict to become:
mydict = {
'a': [[2,4], [5,6]],
'b': [[1,7,9]],
}
If I understand well your question, you want to append a new value to your dictionary if the key already exists. If so, I would use a defaultdict for a simple reason. With a defaultdict you can use the method += to create (if does not exist) or add (if exist) an element :
from collections import defaultdict
# Your dictionaries
mydict = {
'a': [[2,4], [5,6]],
'b': [[1,1], [1,7,9], [6,2,3]],
'c': [['a'], [4,5]],
}
plus_min_dict = {'a': [[3,3]]}
# d is a DefaultDict containing mydict values
d=defaultdict(list,mydict)
# d_new is a DefaultDict containing plus_min_dict dict
d_new = defaultdict(list, plus_min_dict)
# Add all key,values of d in d_new
for k, v in d.items():
d_new[k] += d[k]
print(d_new)
Results :
defaultdict(<class 'list'>, {'c': [['a'], [4, 5]], 'a': [[3, 3], [2, 4], [5, 6]], 'b': [[1, 1], [1, 7, 9], [6, 2, 3]]})
Use an if else loop
mydict = {'a': [[2,4]],}
second_dict = {
'a': [ [5,6]],
'b': [[1,1], [1,7,9]],
'c': [['a'], [4,5]]}
missing_values = {
'a': [5,6],
'b': [1,7,9]}
for key, value in missing_values.items():
if key in mydict:
mydict[key ].append(value)
else:
mydict[key ] = [value]
print(mydict)
Result:
{'a': [[2, 4], [5, 6]], 'b': [[1, 7, 9]]}
To append an item into 'a', you can do this:
mydict['a'] += ['test_item']
Or:
mydict['a'].append('test_item')
You can just append:
mydict = {
'a': [[2,4], [5,6]],
'b': [[1,1], [1,7,9], [6,2,3]],
'c': [['a'], [4,5]],
}
mydict['a'].append([7,8])
mydict['d'] = [0,1]
print(mydict)

Categories