【问题标题】:Filter values inside Python generator expressions在 Python 生成器表达式中过滤值
【发布时间】:2016-10-12 20:33:38
【问题描述】:

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

目前我使用的代码是:

sum(dct[k] for k in lst)

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

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

【问题讨论】:

  • 您不能在生成器表达式中使用try。为什么不使用dct.get(k),如果找不到密钥,它会给你None而不是错误?在找不到密钥的情况下,您的代码的正确行为是什么(例如,它应该算作0)?
  • 如果没有找到密钥,那么它应该继续使用剩余的密钥。 (我会更新我的描述来解释这个案例 - 感谢您注意到这一点)

标签: python dictionary keyerror


【解决方案1】:

好吧,选项很少,首选是使用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

祝你好运!

【讨论】:

  • 伟大而完整的答案。想知道您是否可以在比较这 4 个选项时提供一些见解;具体来说,第三个选项与前两个选项相比如何。其中是否有任何效率提升或更“Pythonic”的方法?
  • @Yannis 谢谢,当然)查看更新的时间指标答案:) 我的猜测获胜者方法是最“Pythonic”的)
【解决方案2】:

你有两个选择:

检查密钥是否存在

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

或使用get

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

如果k 是dct 中的一个键,则dct.get(k, 0) 返回dct[k],否则返回0。

【讨论】:

    【解决方案3】:
    sum(dct[k] for k in lst if k in dct)
    

    【讨论】:

    • 确实很有帮助;其他人也提到了这种方法,据我所知,你的方法不是最快的。对不起
    【解决方案4】:

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

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

    【讨论】:

      【解决方案5】:

      您可以简单地使用.get() 尝试从字典中获取键的值,如果找不到它将返回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
      

      【讨论】:

        猜你喜欢
        • 2018-06-20
        • 2017-12-08
        • 1970-01-01
        • 2014-04-02
        • 2021-12-27
        • 1970-01-01
        • 2021-10-17
        • 2021-04-26
        • 2012-08-20
        相关资源
        最近更新 更多