【问题标题】:How to add or increment a dictionary entry?如何添加或增加字典条目?
【发布时间】:2011-02-07 05:41:49
【问题描述】:

我现在正在重新接触 Python,因为我很喜欢它。但是,我发现自己一遍又一遍地遇到一种模式。我一直在想,一定有更好的方式来表达我想要的东西,而我可能做错了。

我正在编写的代码格式如下:

# foo is a dictionary
if foo.has_key(bar):
  foo[bar] += 1
else:
  foo[bar] = 1

我在我的程序中写了很多。我的第一反应是把它推到一个辅助函数中,但是 python 库经常提供这样的东西。

我缺少一些简单的小语法技巧吗?还是应该这样做?

【问题讨论】:

  • 顺便说一句,你可以说if bar in foo:而不是if foo.has_key(bar):
  • @J.F. Sebastian:+1 使用正则表达式 :-)
  • 我使用 has_key 是因为我认为(我猜错了)它会使用散列函数来查找键而不是搜索列表,因此效率更高。感谢您的提示 - 我会相应地调整我的编码。
  • 4 年后,但我认为对于那些可能最终从谷歌来到这里的人(比如我)来说,这很重要:if key in dict 实际上比 d.has_key(key) 更有效,并且在概念上更好。

标签: python syntax


【解决方案1】:

我不知道这是如何尝试的,但是如果您需要在 dict 键中附加项目...

indicatorDict = {}
indicatorDict[0] = 'Langford'
indicatorDict[1] = 'Esther'
indicatorDict[3] = 14

向其附加项目,无论是迭代还是其他类型:

indicatorDict[0] = np.append(indicatorDict[0],'Auditorium')
indicatorDict[1] = np.append(indicatorDict[1],'Duflo')
indicatorDict[3] = np.append(indicatorDict[3],'November') 

打印...

{0: array(['Langford', 'Auditorium'], dtype='<U10'),
 1: array(['Esther', 'Duflo'], dtype='<U6'),
 3: array(['14', 'November'], dtype='<U11')}

我避免了 Dict 中的第三个键,以表明如果需要,可以将键从一个步骤跳到另一个步骤... :) 希望对您有所帮助!

【讨论】:

    【解决方案2】:

    我做了一些时间比较。几乎相等。不过,单行的.get() 命令是最快的。

    输出:

    get 0.543551800627
    exception 0.587318710994
    haskey 0.598421703081
    

    代码:

    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()
    

    【讨论】:

    • 有趣 - 喜欢看一些测试,尽管您测量的差异很小!我想知道他们会受到更多或更少重复的影响吗?我的预测:异常版本会在 foo[bar] += 1 通常成功时表现最好
    • 增加重复项可以提高异常代码的性能。将 RANDLIST 更改为 [random.randint(0, 100) for i in range(10000)] 产生:获取 0.0955109596252 异常 0.06258893013 haskey 0.0973930358887
    • defaultdict 在这里比较如何?
    【解决方案3】:

    dictget() 方法采用可选的第二个参数,如果找不到请求的键,可以使用该参数提供默认值:

    foo[bar] = foo.get(bar, 0) + 1
    

    【讨论】:

    • 我没有投反对票,但我猜最初的反对者这样做是因为它违反了 DRY(不要重复自己)原则:“foo”和“bar”都被提到了两次。
    • @Tamas:好吧,OPs 版本提到了这三遍:)
    • @Tamas...这似乎是对 DRY 原则的一个相当极端的解释...我通常看到它在重复逻辑的上下文中被提及 - 而不是变量名!这是我书中的一个很好的答案,因为它清晰地传达了逻辑并且可以适应多种场景(任何默认值,任何要执行的功能)
    • 这比公认的答案要好,不需要导入。
    【解决方案4】:

    使用defaultdict

    from collections import defaultdict
    
    foo = defaultdict(int)
    foo[bar] += 1
    

    在 Python >= 2.7 中,您还有一个单独的 Counter 类用于这些目的。对于 Python 2.5 和 2.6,您可以使用其backported version

    【讨论】:

    【解决方案5】:

    您还可以利用异常处理中的控制结构。当您尝试将值分配给不存在的键时,字典会抛出 KeyError 异常:

    my_dict = {}
    try:
        my_dict['a'] += 1
    except KeyError, err:    # in 2.6: `except KeyError as err:`
        my_dict['a'] = 1
    

    【讨论】:

    • 仅仅因为异常处理可以用于控制流并不意味着它应该。
    • AFAIK,执行类似 dict.has_key(key) 之类的操作实际上会尝试访问密钥并在捕获到异常时返回 False。
    【解决方案6】:

    对于 Python >= 2.5,您可以执行以下操作:

    foo[bar] = 1 if bar not in foo else foo[bar]+1
    

    【讨论】:

    • 虽然有效,但并不比 OP 的代码更简洁或易读。
    • @sventechie。我想你可能对可读性和 Pythonic 有一个非常个人化的定义。
    猜你喜欢
    • 1970-01-01
    • 2020-05-04
    • 1970-01-01
    • 2012-09-20
    • 2011-12-30
    • 2020-11-20
    • 1970-01-01
    • 2015-07-12
    • 2016-08-14
    相关资源
    最近更新 更多