Check if a given key already exists in a dictionary and increment it
-
19-08-2019 - |
Question
Given a dictionary, how can I find out if a given key in that dictionary has already been set to a non-None value?
I.e., I want to do this:
my_dict = {}
if (my_dict[key] != None):
my_dict[key] = 1
else:
my_dict[key] += 1
I.e., I want to increment the value if there's already one there, or set it to 1 otherwise.
Solution
You are looking for collections.defaultdict
(available for Python 2.5+). This
from collections import defaultdict
my_dict = defaultdict(int)
my_dict[key] += 1
will do what you want.
For regular Python dict
s, if there is no value for a given key, you will not get None
when accessing the dict -- a KeyError
will be raised. So if you want to use a regular dict
, instead of your code you would use
if key in my_dict:
my_dict[key] += 1
else:
my_dict[key] = 1
OTHER TIPS
I prefer to do this in one line of code.
my_dict = {} my_dict[some_key] = my_dict.get(some_key, 0) + 1
Dictionaries have a function, get, which takes two parameters - the key you want, and a default value if it doesn't exist. I prefer this method to defaultdict as you only want to handle the case where the key doesn't exist in this one line of code, not everywhere.
I personally like using setdefault()
my_dict = {}
my_dict.setdefault(some_key, 0)
my_dict[some_key] += 1
You need the key in dict
idiom for that.
if key in my_dict and not (my_dict[key] is None):
# do something
else:
# do something else
However, you should probably consider using defaultdict
(as dF suggested).
To answer the question "how can I find out if a given index in that dict has already been set to a non-None value", I would prefer this:
try:
nonNone = my_dict[key] is not None
except KeyError:
nonNone = False
This conforms to the already invoked concept of EAFP (easier to ask forgiveness then permission). It also avoids the duplicate key lookup in the dictionary as it would in key in my_dict and my_dict[key] is not None
what is interesting if lookup is expensive.
For the actual problem that you have posed, i.e. incrementing an int if it exists, or setting it to a default value otherwise, I also recommend the
my_dict[key] = my_dict.get(key, default) + 1
as in the answer of Andrew Wilkinson.
There is a third solution if you are storing modifyable objects in your dictionary. A common example for this is a multimap, where you store a list of elements for your keys. In that case, you can use:
my_dict.setdefault(key, []).append(item)
If a value for key does not exist in the dictionary, the setdefault method will set it to the second parameter of setdefault. It behaves just like a standard my_dict[key], returning the value for the key (which may be the newly set value).
Agreed with cgoldberg. How I do it is:
try:
dict[key] += 1
except KeyError:
dict[key] = 1
So either do it as above, or use a default dict as others have suggested. Don't use if statements. That's not Pythonic.
As you can see from the many answers, there are several solutions. One instance of LBYL (look before you leap) has not been mentioned yet, the has_key() method:
my_dict = {}
def add (key):
if my_dict.has_key(key):
my_dict[key] += 1
else:
my_dict[key] = 1
if __name__ == '__main__':
add("foo")
add("bar")
add("foo")
print my_dict
The way you are trying to do it is called LBYL (look before you leap), since you are checking conditions before trying to increment your value.
The other approach is called EAFP (easier to ask forgiveness then permission). In that case, you would just try the operation (increment the value). If it fails, you catch the exception and set the value to 1. This is a slightly more Pythonic way to do it (IMO).
http://mail.python.org/pipermail/python-list/2003-May/205182.html
A bit late but this should work.
my_dict = {}
my_dict[key] = my_dict[key] + 1 if key in my_dict else 1
This isn't directly answering the question, but to me, it looks like you might want the functionality of collections.Counter.
from collections import Counter
to_count = ["foo", "foo", "bar", "baz", "foo", "bar"]
count = Counter(to_count)
print(count)
print("acts just like the desired dictionary:")
print("bar occurs {} times".format(count["bar"]))
print("any item that does not occur in the list is set to 0:")
print("dog occurs {} times".format(count["dog"]))
print("can iterate over items from most frequent to least:")
for item, times in count.most_common():
print("{} occurs {} times".format(item, times))
This results in the output
Counter({'foo': 3, 'bar': 2, 'baz': 1})
acts just like the desired dictionary:
bar occurs 2 times
any item that does not occur in the list is set to 0:
dog occurs 0 times
can iterate over items from most frequent to least:
foo occurs 3 times
bar occurs 2 times
baz occurs 1 times
Here's one-liner that I came up with recently for solving this problem. It's based on the setdefault dictionary method:
my_dict = {}
my_dict[key] = my_dict.setdefault(key, 0) + 1
I was looking for it, didn't found it on web then tried my luck with Try/Error and found it
my_dict = {}
if my_dict.__contains__(some_key):
my_dict[some_key] += 1
else:
my_dict[some_key] = 1