Python dictionary increment - python

In Python it's annoying to have to check whether a key is in the dictionary first before incrementing it:
if key in my_dict:
my_dict[key] += num
else:
my_dict[key] = num
Is there a shorter substitute for the four lines above?

An alternative is:
my_dict[key] = my_dict.get(key, 0) + num

You have quite a few options. I like using Counter:
>>> from collections import Counter
>>> d = Counter()
>>> d[12] += 3
>>> d
Counter({12: 3})
Or defaultdict:
>>> from collections import defaultdict
>>> d = defaultdict(int) # int() == 0, so the default value for each key is 0
>>> d[12] += 3
>>> d
defaultdict(<function <lambda> at 0x7ff2fe7d37d0>, {12: 3})

What you want is called a defaultdict
See http://docs.python.org/library/collections.html#collections.defaultdict

transform:
if key in my_dict:
my_dict[key] += num
else:
my_dict[key] = num
into the following using setdefault:
my_dict[key] = my_dict.setdefault(key, 0) + num

There is also a little bit different setdefault way:
my_dict.setdefault(key, 0)
my_dict[key] += num
Which may have some advantages if combined with other logic.

A solution to shorten the condition can be the following sample:
dict = {}
dict['1'] = 10
dict['1'] = dict.get('1', 0) + 1 if '1' in dict else 1
print(dict)

Any one of .get or .setdefault can be used:
.get() give default value passed in the function if there is no valid key
my_dict[key] = my_dict.get(key, 0) + num
.setdefault () create a key with default value passed
my_dict[key] = my_dict.setdefault(key, 0) + num

Related

How can I write a Python function that counts the number of times a letter occurs in a string?

I've got two problems with the following code
S = "acbcbba"
def count_letters(text):
result = {}
for letter in text:
if letter.isalpha():
if letter.lower() in result.keys():
result[letter.lower()] += 1
else:
result[letter.lower()] = 1
print(result)
return(result)
count_letters(S)
Firstly, I can't figure out how to modify it so it only returns 1 dictionary instead of as many dictionaries as there letters in the string.
Secondly, I then need to be able to access each key to figure out if the value associated with it is odd and return the keys that have odd values associated with them?
Does anyone have any ideas of how to do this?
It isn't returning multiple dictionaries, it is returning 1 dictionary, and printing the others. Just remove your print statement.
Regarding querying for items which have an odd number of counts you can use a list comprehension of the dictionary's items() and filter out by their value (i.e. count) being odd.
>>> d = count_letters(S)
>>> d
{'a': 2, 'c': 2, 'b': 3}
>>> [key for key, value in d.items() if value % 2 == 1]
['b']
If you want a list of the key value pairs then you can do something similar
>>> [(key, value) for key, value in d.items() if value % 2 ==1 ]
[('b', 3)]
All was about an indentation but here is a solution
S = "acbcbba"
def count_letters(text):
result = {}
for letter in text:
if letter.isalpha():
if letter.lower() in result.keys():
result[letter.lower()] += 1
else:
result[letter.lower()] = 1
print(result)
return(result)
count_letters(S)
output
{'a': 2, 'c': 2, 'b': 3}
anyway there was no reason to return if there is print in the function or you could return result only and thereafter print it like the following
S = "acbcbba"
def count_letters(text):
result = {}
for letter in text:
if letter.isalpha():
if letter.lower() in result.keys():
result[letter.lower()] += 1
else:
result[letter.lower()] = 1
return(result)
print(count_letters(S))
You can use built-in functions for that. For counting a specific character, just do S.count('a'). For getting a dictionary with all characters you could do something like that
S = "acbcbba"
my_dict = {k:S.count(k) for k in set(S)}

Add values of same key in a dictionary

My input is a list and I want to convert it into a dictionary and add all values for the same keys. like in the give example in a random list k has two values 1 and 3 so value of k in dictionary will be {'k':4,'D':2}. And then sort it in alphabetic order
Input: ['k:1','D:2','k:3']
Output {'k':4,'D':2}
dlist = ['k:1','D:2','k:3']
dick ={}
for x in dlist:
key,value = x.split(':')
dick[key] = int(value)
print(dick)
I have the above code but I don't know how to add two values for k?
You need to actually add the value to the pre-existing value. In your code now you just overwrite the old value with the new one.
dick = {}
for x in dlist:
key, value = x.split(':')
dick[key] = dick.get(key, 0) + int(value)
dict.get(key, 0) gets the value of the key in the dictionary, with a default of zero
This is possible by making dick a defaultdict. So, now you can just += the value.
from collections import defaultdict
dlist = ['k:1','D:2','k:3']
dick = defaultdict(int)
for x in dlist:
key, value = x.split(':')
dick[key] += int(value)
print(dick)
You can use groupby from itertools to group same values and then sum.
import itertools
a=['k:1','D:2','k:3']
print({k:sum([int(j[1]) for j in v]) for k,v in itertools.groupby([i.split(":") for i in sorted(a)], lambda x: x[0])})
Output
{'D': 2, 'k': 4}

seeking a way to initialize dict in a more efficient way

prior={}
conditionProb={}
Counts={}
for i in range(len(trainingData)):
label=trainingLabels[i]
prior[label]+=1
datum=trainingData[i]
for j in range(len(datum)):
Counts[(i,j,label)]+=1
if(datum[j]>0):
conditionProb[(i,j,label)]+=1
when I run this code, it will report a key error because prior do not initialize first so the value is 0. I can initialize these 3 dict by loops but it seems put too many code to do the work. So I am seeking some other way to do this, e.g. override default method in dict? I am not familiar with python. Any idea is appreciated.
You can use defaultdict to initialize keys to 0:
from collections import defaultdict
prior = defaultdict(lambda: 0)
conditionProb = defaultdict(lambda: 0)
Counts = defaultdict(lambda: 0)
for i, (label, data) in enumerate(zip(trainingLabels, trainingData)):
prior[label] += 1
for j,datum in enumerate(data):
Counts[i, j, label] += 1
if datum > 0:
conditionProb[i, j, label] += 1
You can use defaultdict from the collections module. You construct it passing the type of values in there, in this case an int, plus a default value if it's not set (default is 0). Do it like this:
from collections import defaultdict
my_dict = defaultdict(int)
my_dict['foo'] += 2
You can use Counter:
>>> from collections import Counter
>>> c = Counter()
>>> c['a'] += 2
>>> c
Counter({'a': 2})

In Python merge two dictionaries so that their keys are added/subtracted

I've two dictionaries, output of factorint from sympy.ntheory. I need to merge them so that the common keys gets their values summed up, i.e. MergedDict[key] = Dict1[key] + Dict2[key], while unique keys remain same.
Also I need to get a merged dictionary with the common keys being differenced, i.e. MergedDict[key] = Dict1[key] - Dict2[key]. Here Dict2 keys will be always a subset of Dict1 keys, so no problem of negative numbers.
I've tried to follow this question. But I'm unable to make it work. So far my approach has been as follows:
from sympy.ntheory import factorint
from collections import defaultdict
d=factorint(12)
dd = defaultdict(lambda: defaultdict(int))
for key, values_dict in d.items():
for date, integer in values_dict.items():
dd[key] += integer
for n in range(2,6):
u = factorint(n)
for key, values_dict in u.items():
for date, integer in values_dict.items():
dd[key] += integer
It gives the error AttributeError: 'int' object has no attribute 'items'. The code above in only for the summing up part. Yet to do anything on the differencing part, assuming that summing up can be changed to work for differencing in case of common keys.
Not sure what you goal is but factorint gives you key/value pairs of ints so you should be summing the values, you are trying to call items on each val from the dict which is an integer and obviously not going to work:
from sympy.ntheory import factorint
from collections import defaultdict
d=factorint(12)
dd = defaultdict(int)
for key, val in d.items():
dd[key] += val
for n in range(2, 6):
u = factorint(n)
for key, val in u.items():
dd[key] += val
print(dd)
Output:
defaultdict(<type 'int'>, {2: 5, 3: 2, 5: 1})
factorint being a dict cannot have duplicate keys so the first loop cann be done using update:
d = factorint(12)
dd = defaultdict(int)
dd.update(d)
for n in range(2, 6):
u = factorint(n)
for key, val in u.items():
dd[key] += val
It seems that collections.Counter can do most of what you want. It might be as simple as (untested, I do not have sympy installed):
from collections import Counter
cnt1 = Counter(Dict1)
cnt2 = Counter(Dict2)
sum_cnt = cnt1 + cnt2
diff_cnt = cnt1 - cnt2

dictionary values in python adding values

So here is my problem, i have a dictionary with following key => values:
6bc51fb21fd9eefef4ec97a241733cd59b71e8e14ad70e9068d32002:политичка -> 2
6bc51fb21fd9eefef4ec97a241733cd59b71e8e14ad70e9068d32002:државата -> 2
6bc51fb21fd9eefef4ec97a241733cd59b71e8e14ad70e9068d32002:енергично -> 1
1caa60ebf9459d9cd406f1a03e1719b675dcfaad78292edc7e4a56be:полициска -> 1
I have this code to show the keys needed:
for key, value in count_db.iteritems():
print key[:56]
So now i have:
6bc51fb21fd9eefef4ec97a241733cd59b71e8e14ad70e9068d32002 -> 2
6bc51fb21fd9eefef4ec97a241733cd59b71e8e14ad70e9068d32002 -> 2
6bc51fb21fd9eefef4ec97a241733cd59b71e8e14ad70e9068d32002 -> 1
1caa60ebf9459d9cd406f1a03e1719b675dcfaad78292edc7e4a56be -> 1
I need to merge them into:
6bc51fb21fd9eefef4ec97a241733cd59b71e8e14ad70e9068d32002 -> 5
1caa60ebf9459d9cd406f1a03e1719b675dcfaad78292edc7e4a56be -> 1
I have made this but i have not succeed in doing it correctly:
length_dic=len(count_db.keys())
for key, value in count_db.iteritems():
count_element=key[:56]
#print "%s => %s" % (key[:56], value) #value[:56]
for i in range(length_dic):
i+=1
if count_element == key[:56]:
itr+=int(value)
print i
length_dic=length_dic-1
Any hints?
A trivial approach would be:
result = {}
for key, value in count_db.iteritems():
result[key[:56]] = result.get(key[:56], 0) + value
You could also achieve the same with reduce if you want to get it on one line:
import collections
result = reduce(lambda x,y: x[y[0][:56]] += y[1] , count_db.iteritems(), collections.defaultdict(int))
Given your dictionary as
>>> spam={"6bc51fb21fd9eefef4ec97a241733cd59b71e8e14ad70e9068d32002:AAAA": 2,
"6bc51fb21fd9eefef4ec97a241733cd59b71e8e14ad70e9068d32002:BBBB": 2,
"6bc51fb21fd9eefef4ec97a241733cd59b71e8e14ad70e9068d32002:CCCC": 1,
"1caa60ebf9459d9cd406f1a03e1719b675dcfaad78292edc7e4a56be:DDDD": 1
}
you can somewhat do like the following
>>> bacon=collections.defaultdict(int)
>>> for k,v in [(k[:56],v) for k,v in spam.iteritems()]:
bacon[k]+=v
>>> bacon
defaultdict(<type 'int'>, {'6bc51fb21fd9eefef4ec97a241733cd59b71e8e14ad70e9068d32002': 5, '1caa60ebf9459d9cd406f1a03e1719b675dcfaad78292edc7e4a56be': 1})
>>>
This is exactly what the Counter object (in version 2.7+) is for:
import collections
c = collections.Counter()
for key, value in count_db.iteritems():
c[key[:56]] += value
I didn't understand why you did all that in your code. I think this would do the job:
tmp_dict = {}
for key, value in count_db.iteritems():
count_element=key[:56]
if count_element in tmp_dict:
tmp_dict[count_element] += value
else:
tmp_dict[count_element] = value

Categories

Resources