Related
I am giving the user the ability to check a specific key in a multi-level dictionary. My idea is that they will pass the path to the key like this:
root.subelement1.subelement2.key
This can be of arbitrary length and depth.
Once I have the string (above) from the user, I'll split it and get a list of each individual component:
elements = ['root', 'subelement1', 'subelement2', 'key']
All of this I can do. The next part is where I am stuck. How can I query the dictionary key, specified by the above when it's arbitrary length?
My initial thought was to do something like my_dict[elements[0]][elements[1]]...but that doesn't scale or work when my user doesn't pass exactly the length I expect.
How can I get the data at an arbitrary key depth, in this case?
A couple examples:
User passes country.US.NewYork => I query `my_dict['country']['US']['NewYork']
User passes department.accounting => I query my_dict['department']['accounting']
User passes id => I query my_dict['id']
User passes district.District15.HenryBristow.principal => I query my_dict['district']['District15']['HenryBristow']['principal']
you could do that using reduce which will query the keys in the nested dictionaries:
q = "district.District15.HenryBristow.principal"
my_dict = {"district" : {"District15" : {"HenryBristow" : {"principal" : 12}}}}
from functools import reduce # python 3 only
print(reduce(lambda x,y : x[y],q.split("."),my_dict))
result:
12
If you want to avoid to catch KeyError in case the data doesn't exist with this path, you could use get with a default value as empty dictionary:
reduce(lambda x,y : x.get(y,{}),q.split("."),my_dict)
Trying to get an unknown value returns an empty dictionary. The only drawback is that you don't know from where exactly the path got lost, so maybe leaving the KeyError be raised wouldn't be so bad:
try:
v = reduce(lambda x,y : x[y],q.split("."),my_dict)
except KeyError as e:
print("Missing key: {} in path {}".format(e,q))
v = None
Use recursion. Ex:
root = {
'subelement1': {
'subelement2': {
'key': 'value'
}
}
}
elements = ['subelement1', 'subelement2', 'key']
def getElem(d, keys):
if keys == []:
return None
else:
key = keys[0]
remainingKeys = keys[1:]
if remainingKeys == []:
return d[key]
else:
if type(d[key]) == dict:
return getElem(d[key], remainingKeys)
else:
return None
print(getElem(root, elements))
from a python 2.x perspective, you can do this with reduce.
query_list = keys.split(":")
print reduce(lambda x,y: x[y], [my_dict] + query_list)
But in general, you'll want to do this with a recursive or iterative function if you want to do error handling beyond throwing a KeyError.
You can transverse the dictionary using a for loop:
s = 'root.subelement1.subelement2.key'
d1 = {'root':{'subelement1':{'subelement2':{'key':15, 'key1':18}}}}
new_d = d1
for key in s.split('.'):
new_d = new_d[key]
print(new_d)
Output:
15
u can do this like below
my_dict = someDict
tmpDict = dict(someDict) # a coppy of dict
input = "x.u.z"
array = input.split(".")
for key in array:
tmpDict = tmpDict[key]
print(tmpDict)
but your question is very challenging:
u say if user send country.us then go to my-dict.country.us
but what happen if one of this path in my_dict be a list code will results error
u can handle this by check type
if isinstance(tmpDict , dict ):
tmpDict = tmpDict[key]
else:
# u should say what u want else (a Recursive method u will need)
edit
if user address maybe wrong you should check my_dict have this field or not sample code is below but will be many if i don't like that!
if key not in tmpDict:
print("Bad Path")
return
I am looking to learn how to pass certain keys/values in a dictionary to another function within a for loop. The "certain" keys all share the same initial string and are incremented by a trailing integer like this:
data = {}
data["HMD1"] = [a,b,c]
data["HMD2"] = [d,f,g] #and so on...
There are other keys with dissimilar names witin the same dictionary. Now within a for loop I would like to pass the values for each key that starts with "HMD" to another function. Here is a minimal working example of a failed attempt:
data = {}
data["HMD1"] = [0,2,3]
data["HMD2"] = [5,6,4]
data["not"] = 1237659398
data["HMD3"] = [1,1,1]
def dummyfun(vargin):
print(vargin)
return vargin
for f in range(1,2,1):
out = dummyfun(data[eval(''.join(("HMD",str(f))))])
This was a poor guess, of course it returns an error because eval() tries to evaluate "HMD1" which is not a variable but a key in data. Does anyone know how to do this properly?
You don't need eval at all for this. You only need to build the string with .format for example
for f in range(1,4): #range don't include the end point
out = dummyfun(data["HMD{}".format(f)])
with this you get the desire result. But that will fail if the key is not in the dict, you can check it first, catch the exception or provide a default value in case the desire key is not there
#check first
for f in range(1,4):
key = "HMD{}".format(f)
if key in data:
out = dummyfun(data[key])
#catch the exception
for f in range(1,4):
try:
out = dummyfun(data["HMD{}".format(f)])
except KeyError:
print("key",f,"is not in the data")
#provide a default value
for f in range(1,4):
out = dummyfun(data.get("HMD{}".format(f),None))
Just iterate through the dictionary using a for loop and use an if statement to check for validity of the keys:
for key in yourDict: #a for loop for dict iterates through its keys
if 'HMD' in key: #or you can replace with any other conditional
#DO WHAT YOU WANT TO DO HERE
And here's a quick working example:
>>> data = {'HMD1': [1,2,3], 'HMD23':'heyo mayo', 'HMNOT2':'if this prints, I did something wrong'}
>>> for key in data:
... if 'HMD' in key:
... print data[key]
...
[1, 2, 3]
heyo mayo
With further understand of what you want, you can also look at this backwards and create key strings and print the values that those key's point to:
#let's say you want to print HMD1, HMD2, HMD4, but not anything else
keylist = [#list of keys that you want]
for key in keylist:
if key in data:
print data[key]
and, again, a working example.
>>> data = {'HMD1': [1,2,3], 'HMD3':'heyo mayo, this shouldnt print', 'HMD4':123, 'HMD2':['g', 'h', 'i'], 'HMNOT2':'if this prints, I did something wrong'}
>>> keylist = ['HMD1', 'HMD2', 'HMD4']
>>> for key in keylist:
... if key in data:
... print data[key]
...
[1, 2, 3]
['g', 'h', 'i']
123
Many SO posts show you how to efficiently check the existence of a key in a dictionary, e.g., Check if a given key already exists in a dictionary
How do I do this for a multi level key? For example, if d["a"]["b"] is a dict, how can I check if d["a"]["b"]["c"]["d"] exists without doing something horrendous like this:
if "a" in d and isInstance(d["a"], dict) and "b" in d["a"] and isInstance(d["a"]["b"], dict) and ...
Is there some syntax like
if "a"/"b"/"c"/"d" in d
What I am actually using this for: we have jsons, parsed into dicts using simplejson, that I need to extract values from. Some of these values are nested three and four levels deep; but sometimes the value doesn't exist at all. So I wanted something like:
val = None if not d["a"]["b"]["c"]["d"] else d["a"]["b"]["c"]["d"] #here d["a"]["b"] may not even exist
EDIT: prefer not to crash if some subkey exists but is not a dictionary, e.g, d["a"]["b"] = 5.
Sadly, there isn't any builtin syntax or a common library to query dictionaries like that.
However, I believe the simplest(and I think it's efficient enough) thing you can do is:
d.get("a", {}).get("b", {}).get("c")
Edit: It's not very common, but there is: https://github.com/akesterson/dpath-python
Edit 2: Examples:
>>> d = {"a": {"b": {}}}
>>> d.get("a", {}).get("b", {}).get("c")
>>> d = {"a": {}}
>>> d.get("a", {}).get("b", {}).get("c")
>>> d = {"a": {"b": {"c": 4}}}
>>> d.get("a", {}).get("b", {}).get("c")
4
This isn't probably a good idea and I wouldn't recommend using this in prod. However, if you're just doing it for learning purposes then the below might work for you.
def rget(dct, keys, default=None):
"""
>>> rget({'a': 1}, ['a'])
1
>>> rget({'a': {'b': 2}}, ['a', 'b'])
2
"""
key = keys.pop(0)
try:
elem = dct[key]
except KeyError:
return default
except TypeError:
# you gotta handle non dict types here
# beware of sequences when your keys are integers
if not keys:
return elem
return rget(elem, keys, default)
UPDATE: I ended up writing my own open-source, pippable library that allows one to do this: https://pypi.python.org/pypi/dictsearch
A non-recursive version, quite similar to #Meitham's solution, which does not mutate the looked-for key. Returns True/False if the exact structure is present in the source dictionary.
def subkey_in_dict(dct, subkey):
""" Returns True if the given subkey is present within the structure of the source dictionary, False otherwise.
The format of the subkey is parent_key:sub_key1:sub_sub_key2 (etc.) - description of the dict structure, where the
character ":" is the delemiter.
:param dct: the dictionary to be searched in.
:param subkey: the target keys structure, which should be present.
:returns Boolean: is the keys structure present in dct.
:raises AttributeError: if subkey is not a string.
"""
keys = subkey.split(':')
work_dict = dct
while keys:
target = keys.pop(0)
if isinstance(work_dict, dict):
if target in work_dict:
if not keys: # this is the last element in the input, and it is in the dict
return True
else: # not the last element of subkey, change the temp var
work_dict = work_dict[target]
else:
return False
else:
return False
The structure that is checked is in the form parent_key:sub_key1:sub_sub_key2, where the : char is the delimiter. Obviously - it will match case-sensitively, and will stop (return False) if there's a list within the dictionary.
Sample usage:
dct = {'a': {'b': {'c': {'d': 123}}}}
print(subkey_in_dict(dct, 'a:b:c:d')) # prints True
print(subkey_in_dict(dct, 'a:b:c:d:e')) # False
print(subkey_in_dict(dct, 'a:b:d')) # False
print(subkey_in_dict(dct, 'a:b:c')) # True
This is what I usually use
def key_in_dict(_dict: dict, key_lookup: str, separator='.'):
"""
Searches for a nested key in a dictionary and returns its value, or None if nothing was found.
key_lookup must be a string where each key is deparated by a given "separator" character, which by default is a dot
"""
keys = key_lookup.split(separator)
subdict = _dict
for k in keys:
subdict = subdict[k] if k in subdict else None
if subdict is None: break
return subdict
Returns the key if exists, or None it it doesn't
key_in_dict({'test': {'test': 'found'}}, 'test.test') // 'found'
key_in_dict({'test': {'test': 'found'}}, 'test.not_a_key') // None
Trying to use python to change the value associated to a key in a dictionary and it's not returning the correct output
def fetchAndReplace(dictionary,key,newValue):
keys = dictionary.keys()
for i in keys:
if i == key:
print dictionary[key]
dictionary[key] = newValue
return
else:
return "Nothing"
When I call this one a dictionary {'x':3,'y':2}, with x for key and 6 for newValue
It returns the string nothing, which it shouldn't. I can't find anything wrong with my code so if you could point out the mistake I'm overlooking I'd appreciate it.
The problem is you are returning on the first iteration, so you never get to the second key.
Try this:
def fetchAndReplace(dictionary, key,newValue):
keys = dictionary.keys()
for i in keys:
if i == key:
dictionary[key] = newValue
return dictionary
print fetchAndReplace({'x':3,'y':2}, 'x', 6)
Output:
{'y': 2, 'x': 6}
Furthermore, you can accomplish the same as your function with the dict.update method:
>>> mydict = {'x':3,'y':2}
>>> mydict.update({'x': 6})
>>> print mydict
{'y': 2, 'x': 6}
Hth,
Aaron
I think you are trying to do something along these lines:
def fetchAndReplace(dictionary,key,newValue):
if key in dictionary:
dictionary[key]=newValue
return dictionary
else:
return 'Nothing'
di= {'x':3,'y':2}
print fetchAndReplace(di, 'z', 6)
print fetchAndReplace(di, 'x', 6)
Prints:
Nothing
{'y': 2, 'x': 6}
print statements always help
def fetchAndReplace(dictionary,key,newValue):
keys = dictionary.keys()
print 'keys:', keys
for i in keys:
print 'i:', i, 'i == key:', i == key
if i == key:
print dictionary[key]
dictionary[key] = newValue
return
else:
return "Nothing"
Items in a dictionary are almost arbitrarily ordered, if the conditional statement if i == key fails with the first item in keys, the function will return
I'm so tempted to answer this.
You only need to delete two tab characters (or 8, if you use spaces) in order to make your code work.
Decrease the indentation of else: and return "Nothing"
Result:
def fetchAndReplace(dictionary, key, newValue):
keys = dictionary.keys()
for i in keys:
if i == key:
print dictionary[key]
dictionary[key] = newValue
return
else:
return "Nothing"
dictionary = {"x":1, "y":2}
print "The result is: " + str(fetchAndReplace(dictionary,"x",3))
print "The result is: " + str(fetchAndReplace(dictionary,"z",0))
This will produce:
1
The result is: None
The result is: Nothing
Why? Because by decreasing the indentation, the else will be attached to for, and according to this documentation, the else part in for..else will be executed only when the for loop exits normally (i.e., without break or return), which is why it will iterate over all entries, and only if the key is not found, it will return the string "Nothing". Otherwise it will return None, since you just have the statement return.
But as others had noticed, you would probably want something like this:
def fetchAndReplace(dictionary, key, newValue):
result = dictionary.get(key, "Nothing")
dictionary[key] = newValue
return result
which logic is to save the original value of dictionary[key] in variable result, and if the key is not available, it will be assigned the value Nothing. Then you replace the value of that key with dictionary[key] = newValue, and then return the result.
Running this code:
dictionary = {"x":1, "y":2}
print "The result is: " + fetchAndReplace(dictionary,"x",3)
print "The result is: " + fetchAndReplace(dictionary,"z",0)
will produce
The result is: 1
The result is: Nothing
It seems like you wanted to plan in case of there not being a dictionary. However, you already created one. Take out the return nothing.
I would like to print a specific Python dictionary key:
mydic = {}
mydic['key_name'] = 'value_name'
Now I can check if mydic.has_key('key_name'), but what I would like to do is print the name of the key 'key_name'. Of course I could use mydic.items(), but I don't want all the keys listed, merely one specific key. For instance I'd expect something like this (in pseudo-code):
print "the key name is", mydic['key_name'].name_the_key(), "and its value is", mydic['key_name']
Is there any name_the_key() method to print a key name?
Edit:
OK, thanks a lot guys for your reactions! :) I realise my question is not well formulated and trivial. I just got confused because I realised 'key_name' and mydic['key_name'] are two different things and I thought it would be incorrect to print the 'key_name' out of the dictionary context. But indeed I can simply use the 'key_name' to refer to the key! :)
A dictionary has, by definition, an arbitrary number of keys. There is no "the key". You have the keys() method, which gives you a python list of all the keys, and you have the iteritems() method, which returns key-value pairs, so
for key, value in mydic.iteritems() :
print key, value
Python 3 version:
for key, value in mydic.items() :
print (key, value)
So you have a handle on the keys, but they only really mean sense if coupled to a value. I hope I have understood your question.
Additionally you can use....
print(dictionary.items()) #prints keys and values
print(dictionary.keys()) #prints keys
print(dictionary.values()) #prints values
Hmm, I think that what you might be wanting to do is print all the keys in the dictionary and their respective values?
If so you want the following:
for key in mydic:
print "the key name is" + key + "and its value is" + mydic[key]
Make sure you use +'s instead of ,' as well. The comma will put each of those items on a separate line I think, where as plus will put them on the same line.
dic = {"key 1":"value 1","key b":"value b"}
#print the keys:
for key in dic:
print key
#print the values:
for value in dic.itervalues():
print value
#print key and values
for key, value in dic.iteritems():
print key, value
Note:In Python 3, dic.iteritems() was renamed as dic.items()
The name of the key 'key_name' is 'key_name', therefore
print('key_name')
or whatever variable you have representing it.
In Python 3:
# A simple dictionary
x = {'X':"yes", 'Y':"no", 'Z':"ok"}
# To print a specific key (for example key at index 1)
print([key for key in x.keys()][1])
# To print a specific value (for example value at index 1)
print([value for value in x.values()][1])
# To print a pair of a key with its value (for example pair at index 2)
print(([key for key in x.keys()][2], [value for value in x.values()][2]))
# To print a key and a different value (for example key at index 0 and value at index 1)
print(([key for key in x.keys()][0], [value for value in x.values()][1]))
# To print all keys and values concatenated together
print(''.join(str(key) + '' + str(value) for key, value in x.items()))
# To print all keys and values separated by commas
print(', '.join(str(key) + ', ' + str(value) for key, value in x.items()))
# To print all pairs of (key, value) one at a time
for e in range(len(x)):
print(([key for key in x.keys()][e], [value for value in x.values()][e]))
# To print all pairs (key, value) in a tuple
print(tuple(([key for key in x.keys()][i], [value for value in x.values()][i]) for i in range(len(x))))
Since we're all trying to guess what "print a key name" might mean, I'll take a stab at it. Perhaps you want a function that takes a value from the dictionary and finds the corresponding key? A reverse lookup?
def key_for_value(d, value):
"""Return a key in `d` having a value of `value`."""
for k, v in d.iteritems():
if v == value:
return k
Note that many keys could have the same value, so this function will return some key having the value, perhaps not the one you intended.
If you need to do this frequently, it would make sense to construct the reverse dictionary:
d_rev = dict(v,k for k,v in d.iteritems())
Update for Python3: d.iteritems() is not longer supported in Python 3+ and should be replaced by d.items()
d_rev = {v: k for k, v in d.items()}
# highlighting how to use a named variable within a string:
mapping = {'a': 1, 'b': 2}
# simple method:
print(f'a: {mapping["a"]}')
print(f'b: {mapping["b"]}')
# programmatic method:
for key, value in mapping.items():
print(f'{key}: {value}')
# yields:
# a 1
# b 2
# using list comprehension
print('\n'.join(f'{key}: {value}' for key, value in dict.items()))
# yields:
# a: 1
# b: 2
Edit: Updated for python 3's f-strings...
Make sure to do
dictionary.keys()
rather than
dictionary.keys
import pprint
pprint.pprint(mydic.keys())
Or you can do it that manner:
for key in my_dict:
print key, my_dict[key]
dict = {'name' : 'Fred', 'age' : 100, 'employed' : True }
# Choose key to print (could be a user input)
x = 'name'
if x in dict.keys():
print(x)
What's wrong with using 'key_name' instead, even if it is a variable?
Probably the quickest way to retrieve only the key name:
mydic = {}
mydic['key_name'] = 'value_name'
print mydic.items()[0][0]
Result:
key_name
Converts the dictionary into a list then it lists the first element which is the whole dict then it lists the first value of that element which is: key_name
I'm adding this answer as one of the other answers here (https://stackoverflow.com/a/5905752/1904943) is dated (Python 2; iteritems), and the code presented -- if updated for Python 3 per the suggested workaround in a comment to that answer -- silently fails to return all relevant data.
Background
I have some metabolic data, represented in a graph (nodes, edges, ...). In a dictionary representation of those data, keys are of the form (604, 1037, 0) (representing source and target nodes, and the edge type), with values of the form 5.3.1.9 (representing EC enzyme codes).
Find keys for given values
The following code correctly finds my keys, given values:
def k4v_edited(my_dict, value):
values_list = []
for k, v in my_dict.items():
if v == value:
values_list.append(k)
return values_list
print(k4v_edited(edge_attributes, '5.3.1.9'))
## [(604, 1037, 0), (604, 3936, 0), (1037, 3936, 0)]
whereas this code returns only the first (of possibly several matching) keys:
def k4v(my_dict, value):
for k, v in my_dict.items():
if v == value:
return k
print(k4v(edge_attributes, '5.3.1.9'))
## (604, 1037, 0)
The latter code, naively updated replacing iteritems with items, fails to return (604, 3936, 0), (1037, 3936, 0.
I looked up this question, because I wanted to know how to retrieve the name of "the key" if my dictionary only had one entry. In my case, the key was unknown to me and could be any number of things. Here is what I came up with:
dict1 = {'random_word': [1,2,3]}
key_name = str([key for key in dict1]).strip("'[]'")
print(key_name) # equal to 'random_word', type: string.
Try this:
def name_the_key(dict, key):
return key, dict[key]
mydict = {'key1':1, 'key2':2, 'key3':3}
key_name, value = name_the_key(mydict, 'key2')
print 'KEY NAME: %s' % key_name
print 'KEY VALUE: %s' % value
key_name = '...'
print "the key name is %s and its value is %s"%(key_name, mydic[key_name])
If you want to get the key of a single value, the following would help:
def get_key(b): # the value is passed to the function
for k, v in mydic.items():
if v.lower() == b.lower():
return k
In pythonic way:
c = next((x for x, y in mydic.items() if y.lower() == b.lower()), \
"Enter a valid 'Value'")
print(c)