How to add or increment a dictionary entry?
Question:
I’m currently re-engaging with Python after a long absence and loving it. However, I find myself coming across a pattern over and over. I keep thinking that there must be a better way to express what I want and that I’m probably doing it the wrong way.
The code that I’m writing is in the following form:
# foo is a dictionary
if foo.has_key(bar):
foo[bar] += 1
else:
foo[bar] = 1
I’m writing this a lot in my programs. My first reaction is to push it out to a helper function, but so often the python libraries supply things like this already.
Is there some simple little syntax trick that I’m missing? Or is this the way that it should be done?
Answers:
Use a defaultdict
:
from collections import defaultdict
foo = defaultdict(int)
foo[bar] += 1
In Python >= 2.7, you also have a separate Counter class for these purposes. For Python 2.5 and 2.6, you can use its backported version.
For Python >= 2.5 you can do the following:
foo[bar] = 1 if bar not in foo else foo[bar]+1
You can also take advantage of the control structure in exception handling. A KeyError
exception is thrown by a dictionary when you try to assign a value to a non-existent key:
my_dict = {}
try:
my_dict['a'] += 1
except KeyError, err: # in 2.6: `except KeyError as err:`
my_dict['a'] = 1
The dict
‘s get()
method takes an optional second parameter that can be used to provide a default value if the requested key is not found:
foo[bar] = foo.get(bar, 0) + 1
I did some time comparisons. Pretty much equal. The one-lined .get()
command is fastest, though.
Output:
get 0.543551800627
exception 0.587318710994
haskey 0.598421703081
Code:
import timeit
import random
RANDLIST = [random.randint(0, 1000) for i in range(10000)]
def get():
foo = {}
for bar in RANDLIST:
foo[bar] = foo.get(bar, 0) + 1
def exception():
foo = {}
for bar in RANDLIST:
try:
foo[bar] += 1
except KeyError:
foo[bar] = 1
def haskey():
foo = {}
for bar in RANDLIST:
if foo.has_key(bar):
foo[bar] += 1
else:
foo[bar] = 1
def main():
print 'get', timeit.timeit('get()', 'from __main__ import get', number=100)
print 'exception', timeit.timeit('exception()', 'from __main__ import exception', number=100)
print 'haskey', timeit.timeit('haskey()', 'from __main__ import haskey', number=100)
if __name__ == '__main__':
main()
I don’t know how this was tried, but if you need to append items in dict keys…
indicatorDict = {}
indicatorDict[0] = 'Langford'
indicatorDict[1] = 'Esther'
indicatorDict[3] = 14
Append items to it, be it iteratively or other types:
indicatorDict[0] = np.append(indicatorDict[0],'Auditorium')
indicatorDict[1] = np.append(indicatorDict[1],'Duflo')
indicatorDict[3] = np.append(indicatorDict[3],'November')
Printing …
{0: array(['Langford', 'Auditorium'], dtype='<U10'),
1: array(['Esther', 'Duflo'], dtype='<U6'),
3: array(['14', 'November'], dtype='<U11')}
I avoided 3rd key in Dict to show that if needed keys can be jumped from one step to another… 🙂
Hope it helps!
I’m currently re-engaging with Python after a long absence and loving it. However, I find myself coming across a pattern over and over. I keep thinking that there must be a better way to express what I want and that I’m probably doing it the wrong way.
The code that I’m writing is in the following form:
# foo is a dictionary
if foo.has_key(bar):
foo[bar] += 1
else:
foo[bar] = 1
I’m writing this a lot in my programs. My first reaction is to push it out to a helper function, but so often the python libraries supply things like this already.
Is there some simple little syntax trick that I’m missing? Or is this the way that it should be done?
Use a defaultdict
:
from collections import defaultdict
foo = defaultdict(int)
foo[bar] += 1
In Python >= 2.7, you also have a separate Counter class for these purposes. For Python 2.5 and 2.6, you can use its backported version.
For Python >= 2.5 you can do the following:
foo[bar] = 1 if bar not in foo else foo[bar]+1
You can also take advantage of the control structure in exception handling. A KeyError
exception is thrown by a dictionary when you try to assign a value to a non-existent key:
my_dict = {}
try:
my_dict['a'] += 1
except KeyError, err: # in 2.6: `except KeyError as err:`
my_dict['a'] = 1
The dict
‘s get()
method takes an optional second parameter that can be used to provide a default value if the requested key is not found:
foo[bar] = foo.get(bar, 0) + 1
I did some time comparisons. Pretty much equal. The one-lined .get()
command is fastest, though.
Output:
get 0.543551800627
exception 0.587318710994
haskey 0.598421703081
Code:
import timeit
import random
RANDLIST = [random.randint(0, 1000) for i in range(10000)]
def get():
foo = {}
for bar in RANDLIST:
foo[bar] = foo.get(bar, 0) + 1
def exception():
foo = {}
for bar in RANDLIST:
try:
foo[bar] += 1
except KeyError:
foo[bar] = 1
def haskey():
foo = {}
for bar in RANDLIST:
if foo.has_key(bar):
foo[bar] += 1
else:
foo[bar] = 1
def main():
print 'get', timeit.timeit('get()', 'from __main__ import get', number=100)
print 'exception', timeit.timeit('exception()', 'from __main__ import exception', number=100)
print 'haskey', timeit.timeit('haskey()', 'from __main__ import haskey', number=100)
if __name__ == '__main__':
main()
I don’t know how this was tried, but if you need to append items in dict keys…
indicatorDict = {}
indicatorDict[0] = 'Langford'
indicatorDict[1] = 'Esther'
indicatorDict[3] = 14
Append items to it, be it iteratively or other types:
indicatorDict[0] = np.append(indicatorDict[0],'Auditorium')
indicatorDict[1] = np.append(indicatorDict[1],'Duflo')
indicatorDict[3] = np.append(indicatorDict[3],'November')
Printing …
{0: array(['Langford', 'Auditorium'], dtype='<U10'),
1: array(['Esther', 'Duflo'], dtype='<U6'),
3: array(['14', 'November'], dtype='<U11')}
I avoided 3rd key in Dict to show that if needed keys can be jumped from one step to another… 🙂
Hope it helps!