This question already has answers here:
Access nested dictionary items via a list of keys?
(20 answers)
Closed 4 years ago.
If I have a nested dictionary
mydict={'a1':{'b1':1}, 'a2':2}
and a list of indexes index = ['a1', 'b1'] leading to an inner value, is there a pythonic / one-liner way to get that value, i.e. without resorting to a verbose loop like:
d = mydict
for idx in index:
d = d[idx]
print(d)
You can use functools.reduce.
>>> from functools import reduce
>>> mydict = {'a1':{'b1':1}, 'a2':2}
>>> keys = ['a1', 'b1']
>>> reduce(dict.get, keys, mydict)
1
dict.get is a function that takes two arguments, the dict and a key (and another optional argument not relevant here). mydict is used as the initial value.
In case you ever need the intermediary results, use itertools.accumulate.
>>> from itertools import accumulate
>>> list(accumulate([mydict] + keys, dict.get))
[{'a1': {'b1': 1}, 'a2': 2}, {'b1': 1}, 1]
Unfortunately, the function does not take an optional initializer argument, so we are prepending mydict to keys.
Related
This question already has answers here:
How to construct nested dictionary comprehension in Python with correct ordering?
(2 answers)
Closed 2 years ago.
I'm trying to convert this list:
data = [{'A': 123}, {'B': 456}, {'C': 789}]
To this dictionary:
{'A': 123, 'B': 456, 'C': 789}
By using dictionary comprehension:
{key: value for key, value in dictionary.items() for dictionary in data}
Exception:
NameError: name 'dictionary' is not defined
You need to switch your iteration logic. Default order of iteration inside dictionary (or list) comprehension goes from left to right:
>>> data = [{'A': 123}, {'B': 456}, {'C': 789}]
>>> {k: v for d in data for k, v in d.items()}
{'A': 123, 'B': 456, 'C': 789}
You can create nested dictionary comprehension, list comprehension or generator expression using {}, [] and () respectively which are the exceptions for the left to right execution order I mentioned earlier. All these operations create new objects, and they execute inside their own scope.
This question already has answers here:
Nested defaultdict of defaultdict
(11 answers)
Closed 5 years ago.
I want to deal with a nested dictionary in python for purpose of storing unique data. However, I don't know what the right way to do it. I tried the following:
my_dict = collections.defaultdict(dict)
my_dict[id1][id2][id2][id4] = value
but it causes KeyError.
What is the right way to do so?
If you want to create a nested defaultdict to as many depths as you want then you want to set the default type of the defaultdict to a function that returns a defaultdict with the same type. So it looks a bit recursive.
from collections import defaultdict
def nest_defaultdict():
return defaultdict(nest_defaultdict)
d = defaultdict(nest_defaultdict)
d[1][2][3] = 'some value'
print(d)
print(d[1][2][3])
# Or with lambda
f = lambda: defaultdict(f)
d = defaultdict(f)
If you don't require any arbitrary depth then Fuji Clado's answer demonstrates setting up the nested dict and accessing it.
One Simple Approach
mainDict = {}
mainDict['id1']={}
mainDict['id1']['id2'] ={}
mainDict['id1']['id2']['id3'] = 'actualVal'
print(mainDict)
# short explanation of defaultdict
import collections
# when a add some key to the mainDict, mainDict will assgin
# an empty dictionary as the value
mainDict = collections.defaultdict(dict)
# adding only key, The value will be auto assign.
mainDict['key1']
print(mainDict)
# defaultdict(<class 'dict'>, {'key1': {}})
# here adding the key 'key2' but we are assining value of 2
mainDict['key2'] = 2
print(mainDict)
#defaultdict(<class 'dict'>, {'key1': {}, 'key2': 2})
# here we are adding a key 'key3' into the mainDict
# mainDict will assign an empty dict as the value.
# we are adding the key 'inner_key' into that empty dictionary
# and the value as 10
mainDict['key3']['inner_key'] = 10
print(mainDict)
#defaultdict(<class 'dict'>, {'key1': {}, 'key2': 2, 'key3': {'inner_key': 10}})
This question already has answers here:
Initialize List to a variable in a Dictionary inside a loop
(2 answers)
Closed 5 years ago.
I have a dictionary that needs to create a key when the key first shows up and adds a value for it, later on, keeps updating the key with values by appending these values to the previous value(s), I am wondering how to do that.
outter_dict = defaultdict(dict)
num_index = 100
outter_dict['A'].update({num_index: 1})
outter_dict['A'].update({num_index: 2})
2 will replace 1 as the value for key 100 of the inner dict of outter_dict, but ideally, it should look like,
'A': {100:[1,2]}
UPDATE
outter_dict = defaultdict(list)
outter_dict['A'][1].append(2)
but I got
IndexError: list index out of range
if I do
dict['A'][1] = list()
before assign any values to 1, I got
IndexError: list assignment index out of range
You can use a collections.defaultdict:
from collections import defaultdict
d = defaultdict(list)
num_index = 100
d[num_index].append(1)
d[num_index].append(2)
print(dict(d))
Output:
{100: [1, 2]}
Regarding your most recent edit, you want to use defautldict(dict) and setdefault:
outter_dict = defaultdict(dict)
outter_dict["A"].setdefault(1, []).append(2)
print(dict(outter_dict))
Output:
{'A': {1: [2]}}
This question already has answers here:
Extract a subset of key-value pairs from dictionary?
(14 answers)
Filter dict to contain only certain keys?
(22 answers)
Closed 5 years ago.
Dictionary:
d = {'a':[2,3,4,5],
'b':[1,2,3,4],
'c':[5,6,7,8],
'd':[4,2,7,1]}
I want to have d_new which containes only b and c items.
d_new = {'b':[1,2,3,4],
'c':[5,6,7,8]}
I want a scalable solution
EDIT:
I also need a method to create a new dictionary by numbers of items:
d_new_from_0_to_2 = {'a':[2,3,4,5],
'b':[1,2,3,4]}
If you want a general way to pick particular keys (and their values) from a dict, you can do something like this:
d = {'a':[2,3,4,5],
'b':[1,2,3,4],
'c':[5,6,7,8],
'd':[4,2,7,1]}
selected_keys = ['a','b']
new_d = { k: d[k] for k in selected_keys }
Gives:
{'a': [2, 3, 4, 5], 'b': [1, 2, 3, 4]}
I think that in Python 2.6 and earlier you would not be able to use a dict comprehension, so you would have to use:
new_d = dict((k,d[k]) for k in selected_keys)
Is this what you want?
new_d = dict(b=d.get('b'), c=d.get('c'))
This question already has answers here:
Checking a nested dictionary using a dot notation string "a.b.c.d.e", automatically create missing levels
(5 answers)
How can I return a default value for an attribute? [duplicate]
(7 answers)
Closed 8 years ago.
I have a document like this:
>>> k = {'finance_pl':{'S':{'2008':45,'2009':34}}}
Normal way to access is:
>>> k['finance_pl']['S']
{'2008': 45, '2009': 34}
But, in my case the end user will give me input as finance_pl.S
I can split this and access the dictionary like this:
>>> doc_list = doc.split('.')
>>> k[doc_list[0]][doc_list[1]]
{'2008': 45, '2009': 34}
But, I don't want to do this, since the dictionary structure may change the and
user can give something like this finance_pl.new.S instead of k['finance_pl']['S'] or k[doc_list[0]][doc_list[1]].
I need something to apply the users input directly (Ex: if input is finance_pl.new.S, I should be able to apply this .split('.') method to the users input and apply directly).
What is the elegant way to do that ?
I'd simply loop over all the parts:
def getter(somedict, key):
parts = key.split(".")
for part in parts:
somedict = somedict[part]
return somedict
after which we have
>>> getter(k, "finance_pl.S")
{'2008': 45, '2009': 34}
or
>>> getter({"a": {"b": {"c": "d"}}}, "a")
{'b': {'c': 'd'}}
>>> getter({"a": {"b": {"c": "d"}}}, "a.b.c")
'd'
You could go for something like:
k = {'finance_pl':{'S':{'2008':45,'2009':34}}}
print reduce(dict.__getitem__, 'finance_pl.S.2009'.split('.'), k)
# 34
If you're using Python 3.x, you'll need a from functools import reduce in there...
>>> k = {'finance_pl':{'S':{'2008':45,'2009':34}}}
>>> ui = 'finance_pl.S'
>>> def getter(adict, key):
... return reduce(dict.get, key.split('.'), adict)
...
>>> getter(k, ui)
{'2008': 45, '2009': 34}
>>>
userkey = 'finance_pl.new.S'
for key in userkey.split('.'):
k = k[key]
# the final value of k is the one you want
So basically just iterate on every subkey and retrieve the inner dictionary until you're out of subkeys