37

I have a dictionary and I would like to get some values from it based on some keys. For example, I have a dictionary for users with their first name, last name, username, address, age and so on. Let's say, I only want to get one value (name) - either last name or first name or username but in descending priority like shown below:

(1) last name: if key exists, get value and stop checking. If not, move to next key.

(2) first name: if key exists, get value and stop checking. If not, move to next key.

(3) username: if key exists, get value or return null/empty

#my dict looks something like this
myDict = {'age': ['value'], 'address': ['value1, value2'],
          'firstName': ['value'], 'lastName': ['']}

#List of keys I want to check in descending priority: lastName > firstName > userName
keySet = ['lastName', 'firstName', 'userName']

What I tried doing is to get all the possible values and put them into a list so I can retrieve the first element in the list. Obviously it didn't work out.

tempList = []

for key in keys:
    get_value = myDict.get(key)
    tempList .append(get_value)

Is there a better way to do this without using if else block?

codeforester
  • 39,467
  • 16
  • 112
  • 140
Cryssie
  • 3,047
  • 10
  • 54
  • 81

4 Answers4

50

One option if the number of keys is small is to use chained gets:

value = myDict.get('lastName', myDict.get('firstName', myDict.get('userName')))

But if you have keySet defined, this might be clearer:

value = None
for key in keySet:
    if key in myDict:
        value = myDict[key]
        break

The chained gets do not short-circuit, so all keys will be checked but only one used. If you have enough possible keys that the extra lookups matter, use the for loop.

Peter DeGlopper
  • 36,326
  • 7
  • 90
  • 83
  • Does this check if the key exists first before trying to retrieve it? – Cryssie Jun 25 '13 at 22:45
  • Yes. That's that the `in` test does. – Peter DeGlopper Jun 25 '13 at 22:48
  • Do you mind explaining how does the value = myDict.get(... part work? – Cryssie Jun 25 '13 at 23:07
  • 5
    `get` takes an optional second parameter. If the key isn't in the dictionary, that second parameter will be returned, or `None` if you didn't specify one. So if `lastName` isn't in the dict, it'll evaluate the second `get` and so on. – Peter DeGlopper Jun 25 '13 at 23:09
  • Thanks! That's exactly what I need. I didn't know I can do that. – Cryssie Jun 25 '13 at 23:21
  • The problem here is that the arguments are evaluated *before* the function call and any logic inside it. Thus, even if `'lastName'` exists in `myDict`, `myDict.get('firstName', myDict.get('userName'))` is evaulated and just thrown away. `value = myDict.get('lastName') or myDict.get('firstName') or myDict('userName')` is almost equivalent but much more efficient and readable. – musiphil Jun 09 '15 at 17:10
  • Yes, `get` does not short-circuit. If I were in a situation where that mattered I'd probably use the for loop - if nothing else, the `or` chain will do the wrong thing if the key is in the dictionary with a value that's `False` when evaluated as a boolean. I also dislike using boolean operators for non-boolean purposes, but that's less important. – Peter DeGlopper Jun 09 '15 at 17:41
26

Use .get(), which if the key is not found, returns None.

for i in keySet:
    temp = myDict.get(i)
    if temp is not None:
        print temp
        break
Jatriplazx
  • 30
  • 9
TerryA
  • 58,805
  • 11
  • 114
  • 143
3

If we encapsulate that in a function we could use recursion and state clearly the purpose by naming the function properly (not sure if getAny is actually a good name):

def getAny(dic, keys, default=None):
    return (keys or default) and dic.get(keys[0], 
                                         getAny( dic, keys[1:], default=default))

or even better, without recursion and more clear:

def getAny(dic, keys, default=None):
    for k in keys: 
        if k in dic:
           return dic[k]
    return default

Then that could be used in a way similar to the dict.get method, like:

getAny(myDict, keySet)

and even have a default result in case of no keys found at all:

getAny(myDict, keySet, "not found")
olivecoder
  • 2,858
  • 23
  • 22
2

You can use myDict.has_key(keyname) as well to validate if the key exists.

Edit based on the comments -

This would work only on versions lower than 3.1. has_key has been removed from Python 3.1. You should use the in operator if you are using Python 3.1

Nikhil Gupta
  • 1,708
  • 1
  • 23
  • 38
  • 4
    Just to update the readers, `has_key` has been removed in Python 3.x, use `keyname in myDict` instead. https://docs.python.org/3.1/whatsnew/3.0.html#builtins – pangyuteng Dec 02 '14 at 21:18
  • You should use the `in` operator if you're using Python 2.2 or later, since that's the first version `in` for mapping types was introduced and `has_key` was deprecated. – Peter DeGlopper Jun 09 '15 at 18:10