问题
I have a dictionary dct
for which I want each of its values to be summed provided their corresponding keys exist in a specified list lst
.
The code I am using so far is:
sum(dct[k] for k in lst)
In the above generator expression I would like to handle the KeyError
in case a key from the list is not found inside the dictionary. I cannot seem to find how to implement (syntax-wise) either a try
-except
approach, nor an if
-else
approach inside this generator expression.
In case a key from the list is not found inside the dictionary, then it should carry on getting the other values. The end result of the sums should not be affected by any missing keys. In case none of the keys exist, then zero should be the sum's result.
回答1:
Well, there are few options, preferred one is to use dict.get():
# 1
sum(dct.get(k, 0) for k in lst)
# 2
sum(dct[k] for k in lst if k in dct)
Also one of the option is to filter lst
before iteraring over it:
sum(dct[k] for k in filter(lambda i: i in dct, lst))
And you can use reduce function on filtered list as an alternative to sum
:
reduce(lambda a, k: a + dct[k], filter(lambda i: i in dct, lst))
Now let's find fastest approach with timeit:
from timeit import timeit
import random
lst = range(0, 10000)
dct = {x:x for x in lst if random.choice([True, False])}
via_sum = lambda:(sum(dct.get(k, 0) for k in lst))
print("Via sum and get: %s" % timeit(via_sum, number=10000))
# Via sum and get: 16.725695848464966
via_sum_and_cond = lambda:(sum(dct[k] for k in lst if k in dct))
print("Via sum and condition: %s" % timeit(via_sum_and_cond, number=10000))
# Via sum and condition: 9.4715681076
via_reduce = lambda:(reduce(lambda a, k: a + dct[k], filter(lambda i: i in dct, lst)))
print("Via reduce: %s" % timeit(via_reduce, number=10000))
# Via reduce: 19.9522120953
So the fastest option is to sum items via if statement within generator expression
sum(dct[k] for k in lst if k in dct) # Via sum and condition: 9.4715681076
Good Luck !
回答2:
You have two options:
Checking if the key exists
sum(dct[k] for k in lst if k in dct)
or using get
sum(dct.get(k, 0) for k in lst)
where dct.get(k, 0)
returns dct[k]
if k
is a key in dct
or 0
if not.
回答3:
sum(dct[k] for k in lst if k in dct)
回答4:
You can use the get
-method of dictionaries, to provide a default value if not found:
sum(dct.get(k, 0) for k in lst)
回答5:
You can simply use .get() to attempt to get the value for the key from the dictionary, and should it not be found will return None
, or your provided default parameter which would be 0 in this case.
>>> dct = {1:2, 3:4, 5:6}
>>> lst = [1,5]
>>> sum(dct.get(k, 0) for k in lst)
8
Should some (or all) of the keys not exist, the sum will still function properly.
>>> lst = [10, 11]
>>> sum(dct.get(k, 0) for k in lst)
0
来源:https://stackoverflow.com/questions/37772551/filter-values-inside-python-generator-expressions