过滤 Python 生成器表达式中的值

Filter values inside Python generator expressions

我有一个字典 dct,我希望对它的每个值求和,前提是它们的对应键存在于指定列表 lst

目前我使用的代码是:

sum(dct[k] for k in lst)

在上面的生成器表达式中,我想处理 KeyError 以防在字典中找不到列表中的键。我似乎找不到如何在这个生成器表达式中实现(语法方面)try-except 方法,也找不到 if-else 方法。

如果在字典中找不到列表中的 键,则应继续获取其他值求和的最终结果不应受到任何缺失键的影响。如果存在 none 个键,则总和的结果应为零。

sum(dct[k] for k in lst if k in dct)

您可以简单地使用 .get() 尝试从字典中获取键的值,如果找不到,将 return None 或您提供的默认参数在这种情况下将为 0。

>>> dct = {1:2, 3:4, 5:6}
>>> lst = [1,5]
>>> sum(dct.get(k, 0) for k in lst)
8    

如果某些(或全部)键不存在,总和仍将正常运行。

>>> lst = [10, 11]
>>> sum(dct.get(k, 0) for k in lst)
0

您有两个选择:

检查密钥是否存在

sum(dct[k] for k in lst if k in dct)

或使用get

sum(dct.get(k, 0) for k in lst)

其中 dct.get(k, 0) returns dct[k] 如果 kdct 中的键,如果不是 0

您可以使用get-字典的方法,如果找不到则提供默认值:

sum(dct.get(k, 0) for k in lst)

好吧,选项很少,首选是使用 dict.get():

# 1
sum(dct.get(k, 0) for k in lst)
# 2
sum(dct[k] for k in lst if k in dct)

还有一种选择是在迭代之前过滤 lst

sum(dct[k] for k in filter(lambda i: i in dct, lst))

并且您可以在筛选列表中使用 reduce function 作为 sum 的替代方法:

reduce(lambda a, k: a + dct[k], filter(lambda i: i in dct, lst))

现在让我们用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

所以最快的选择是通过生成器表达式中的 if 语句对项目求和

sum(dct[k] for k in lst if k in dct) # Via sum and condition: 9.4715681076

祝你好运!