lets say I have the following dict structure and a list of keys.
d = {
'a': {
'b': {
'c': 'value'
}
}
}
keyList = ['a', 'b', 'c']
What is a pythonic way to reference the value of the c key in a dynamic way? In a static way I would say something like d[a][b][c] however if my keyList is dynamic and I need to reference the value at runtime is there a way to do this? the len of keyList is variable.
The main problem is i really don't know what to search. I tried things like dynamic dictionary path but couldn't get anything remotely close
You can use functools.reduce with the input dict as the starting value and dict.get as the reduction function:
from functools import reduce
print(reduce(dict.get, keyList, d))
This outputs:
value
Demo: https://replit.com/#blhsing/QuintessentialAntiqueMath
Related
I am facing a problem where I have to merger different elements of a dictionary based on some condition. What is the most pythonic way to achieve that?
For example , I have the below dictionary
dict = {
'a': [element1 , element2]
'b': [element2, element3]
'c': [element4, element5, element1]
'd': []
}
My resulting dictionary should be
dict = {
'a': [element1, element2, element3, element4, element5]
}
What would be the best way to achieve that?
I want to merge them based upon condition which is evaluated by is_compatible method. So lets' say I will merge two elements if this function returns true
Is there a way I can do this?
result = {
'a': list(set().union(*input_dict.values()))
}
I don't clearly get what you want to do, but it seems like you want to combine all lists as a set. You can do something like this:
new_list = []
for element in dict.values():
for value in element:
new_list.append(element)
new_list = list(set(new_list))
new_dict = {
dict.keys[0]: new_list
}
Hope this helps!
I have a function to create a dictionary with specific keys, which accepts a parameter to specify what each key's "default" value should be.
def new_dict(entrys_default=0):
my_dict = {}
for k in ['a', 'b', 'c']:
my_dict[k] = entrys_default
return my_dict
The issue is that when I call it with new_dict(entrys_default=[]) so that each entry in the dictionary is created with a new empty list as its value, when I then update one entry with returned_dict['a'].append(123) then all entries are updated:
{'a': [123], 'b': [123], 'c': [123]}
This doesn't happen when using an integer, and I understand that it is because the entrys_default is immutable when it is an integer, but is a reference to the same list when it is a list or dictionary.
I want to be able to have this function work the same as it does for integer parameters with lists and dictionaries as entrys_default - i.e. each entry has its own list/dictionary - but want to keep the function flexible to also work for integers.
Can anyone please suggest the best way to go about this?
Do what collections.defaultdict does; instead of taking an "example" default value, take a function that returns the desired default value. Then call that function and use its return value to initialize each element of the dict being constructed.
def new_dict(make_default=int): # int() == 0
my_dict = {}
for k in ['a', 'b', 'c']:
my_dict[k] = make_default()
return my_dict
d = new_dict(list) # list() == [], but a distinct list each time it is called
d['a'].append(123)
assert d['a'] != d['b']
I want to insert a key-value pair into dict if key not in dict.keys().
Basically I could do it with:
if key not in d.keys():
d[key] = value
But is there a better way? Or what's the pythonic solution to this problem?
You do not need to call d.keys(), so
if key not in d:
d[key] = value
is enough. There is no clearer, more readable method.
You could update again with dict.get(), which would return an existing value if the key is already present:
d[key] = d.get(key, value)
but I strongly recommend against this; this is code golfing, hindering maintenance and readability.
Use dict.setdefault():
>>> d = {'key1': 'one'}
>>> d.setdefault('key1', 'some-unused-value')
'one'
>>> d # d has not changed because the key already existed
{'key1': 'one'}
>>> d.setdefault('key2', 'two')
'two'
>>> d
{'key1': 'one', 'key2': 'two'}
Since Python 3.9 you can use the merge operator | to merge two dictionaries. The dict on the right takes precedence:
new_dict = old_dict | { key: val }
For example:
new_dict = { 'a': 1, 'b': 2 } | { 'b': 42 }
print(new_dict) # {'a': 1, 'b': 42}
Note: this creates a new dictionary with the updated values.
With the following you can insert multiple values and also have default values but you're creating a new dictionary.
d = {**{ key: value }, **default_values}
I've tested it with the most voted answer and on average this is faster as it can be seen in the following example, .
Speed test comparing a for loop based method with a dict comprehension with unpack operator method.
if no copy (d = default_vals.copy()) is made on the first case then the most voted answer would be faster once we reach orders of magnitude of 10**5 and greater. Memory footprint of both methods are the same.
You can also use this solution in only one line of code:
dict[dict_key] = dict.get(dict_key,value)
The second argument of dict.get is the value you want to assign to the key in case the key does not exist. Since this evaluates before the assignment to dict[dict_key] = , we can be sure that they key will exist when we try to access it.
Consider following dictionary:
dict1 = {"A":{"B":"C"}}
print(dict1["A"]["B"])
This prints 'C'
I can now modify my dictionary like this
dict1["A"]["B"] = "D"
dict1["A"]["E"] = "F"
dict1["B"] = "G"
print(dict1)
And the output is
{'A': {'B': 'D', 'E': 'F'}, 'B': 'G'}
but I can't do this:
dict1["C"]["H"] = ["I"]
this however works:
dict2 = {"H":"I"}
dict1["C"] = dict2
print(dict1)
Output:
{'A': {'B': 'D', 'E': 'F'}, 'B': 'G', 'C': {'H': 'I'}}
Is there an alternative that doesn't require creating an additional dictionary?
I am just playing around to learn the language and not working on a concrete project.
Still, any help would be appreciated
Why would dict1["C"]["H"] = ["I"] work if there is no element "C" in dict1?
Do this:
dict1["C"] = {}
dict1["C"]["H"] = ["I"]
You haven't created the dictionary C yet. In python you must first create it before editing it. Like this:
dict1 = {}
dict1["C"] = {} # First create it before modifying it
dict1["C"]["H"] = ["I"]
print(dict1)
Let me explain.
foomain["C"] = 'blah'
sets it, but
foomain['C']['H'] = 'blah'
attempts to find foomain['C'], and fails. If it worked, it would then take that dictionary and use the assignment operator on it to assign blah to ['C']['H'].
It's like saying:
Okay, go find `foomain['C']`, then assign 'blah' to key 'H'
Instead of:
Okay, assign 'blah' to `foomain['C']['H']`
In other words, assignment and getting are entirely different in python.
dict1["C"]["H"] = ["I"]
In the above, the problem is that dict1["C"] has not been initialized, and so it is not known whether it is a dict and can be assigned a sub-element like ["H"] (or whether it is just, say, an integer and assigning to ["H"] would be an error).
There are packages to enable what you're talking about, and using a defaultdict would work for a single level of nestedness. But especially if you are starting out, it's probably better that you deal with such things explicitly.
val = dict1.get("C")
if isinstance(val, dict)
dict1["C"]["H"] = "I"
else
dict["C"] = {"H": "I"}
You can use setdefault which would assign default value in case of key error.
dict1.setdefault('C', {})['H'] = 'I'
Or you can altogether use defaultdict instead of dict.
from collections import defaultdict
There's a one-liner tree in https://gist.github.com/hrldcpr/2012250. It was posted as a cute hack, but works reasonably well.
from collections import defaultdict
def tree(): return defaultdict(tree)
users = tree()
users['harold']['username'] = 'hrldcpr'
users['handler']['username'] = 'matthandlersux'
Because of the defaultdict, each access on an undefined key generates a new value, and because of the recursion the new value will also be a new tree.
Imagine you have a dictionary in python: myDic = {'a':1, 'b':{'c':2, 'd':3}}. You can certainly set a variable to a key value and use it later, such as:
myKey = 'b'
myDic[myKey]
>>> {'c':2, 'd':3}
However, is there a way to somehow set a variable to a value that, when used as a key, will dig into sub dictionaries as well? Is there a way to accomplish the following pseudo-code in python?
myKey = "['b']['c']"
myDic[myKey]
>>> 2
So first it uses 'b' as a key, and whatever is reurned it then uses 'c' as a key on that. Obviously, it would return an error if the value returned from the first lookup is not a dictionary.
No, there is nothing you can put into a variable so that myDict[myKey] will dig into the nested dictionaries.
Here is a function that may work for you as an alternative:
def recursive_get(d, keys):
if len(keys) == 1:
return d[keys[0]]
return recursive_get(d[keys[0]], keys[1:])
Example:
>>> myDic = {'a':1, 'b':{'c':2, 'd':3}}
>>> recursive_get(myDic, ['b', 'c'])
2
No, not with a regular dict. With myDict[key] you can only access values that are actually values of myDict. But if myDict contains other dicts, the values of those nested dicts are not values of myDict.
Depending on what you're doing with the data structure, it may be possible to get what you want by using tuple keys instead of nested dicts. Instead of having myDic = {'b':{'c':2, 'd':3}}, you could have myDic = {('b', 'c'):2, ('b', 'd'): 3}. Then you can access the values with something like myDic['b', 'c']. And you can indeed do:
val = 'b', 'c'
myDic[val]
AFAIK, you cannot. If you think about the way python works, it evaluates inside out, left to right. [] is a shorthand for __getitem__ in this case. Thus you would need to parse the arguments you are passing into __getitem__ (whatever you pass in) and handle that intelligently. If you wanted to have such behavior, you would need to subclass/write your own dict class.
myDict = {'a':1, 'b':{'c':2, 'd':3}}
k = 'b'
myDict.get(k) should give
{'c':2, 'd':3}
and either
d.get(k)['c']
OR
k1 = 'c'
d.get(k).key(k1) should give 2
Pretty old question. There is no builtin function for that.
Compact solution using functools.reduce and operator.getitem:
from functools import reduce
from operator import getitem
d = {'a': {'b': ['banana', 'lemon']}}
p = ['a', 'b', 1]
v = reduce(getitem, p, d)
# 'lemon'