【问题标题】:Set value in dictionary if value not there? [duplicate]如果值不存在,则在字典中设置值? [复制]
【发布时间】:2023-03-03 06:03:25
【问题描述】:

我正在使用字典来存储一堆计数器,其中每个计数器都在计算文件类型(.wav、.mp3 等)的出现次数。

filetypecounter = {}

当我遇到某种文件类型时,我希望能够以 Python 的方式增加计数器。所以我在想……

filetypecounter[filetype] +=1

但是,如果文件类型不在字典中,我想将其实例化为 1。 所以我的逻辑是如果存在文件类型计数器,则将计数器值加 1,否则将其设置为 1。

if filetype not in filetypecounter:
    filetypecounter[filetype] = 1
else: 
    filetypecounter[filetype] +=1

有没有更pythonic的方式?

【问题讨论】:

    标签: python


    【解决方案1】:
    from collections import defaultdict
    
    filetypecounter = defaultdict(int)
    filetypecounter[filetype] += 1
    

    from collections import Counter
    
    filetypecounter = Counter()
    filetypecounter.update([filetype])
    

    关于信息,如果您必须使用dict,您的解决方案(检查密钥是否存在)是一个合理的解决方案。也许一个更“pythonic”的解决方案可能是:

    filetypecounter = {}
    filetypecounter[filetype] = filetypecounter.get(filetype, 0) + 1
    

    实际上,这个和其他建议只是同一主题的变体。我会使用计数器。

    【讨论】:

      【解决方案2】:

      看起来你想要的是collections.defaultdict,或者对于 Python 2.7 及更高版本是 collections.Counter

      【讨论】:

        【解决方案3】:

        这组答案很好地涵盖了使用collections.Counter,但这可能不是最快的选择。

        一种较老的方法是这样的:

        >>> d={}
        >>> for ext in ('.mp3','.mp3','.m4a','.mp3','.wav','.m4a'):
        ...    d[ext]=d.setdefault(ext,0)+1
        ... 
        >>> d
        {'.mp3': 3, '.wav': 1, '.m4a': 2}
        

        这也不是最快的,但比collections.Counter

        这些方法中有benchmarks,默认字典、try/except 或您的原始方法是最快的。

        我在这里复制(并扩展)了基准:

        import urllib2
        import timeit
        
        response = urllib2.urlopen('http://pastebin.com/raw.php?i=7p3uycAz')
        hamlet = response.read().replace('\r\n','\n')
        LETTERS = [w for w in hamlet]
        WORDS = hamlet.split(' ')
        fmt='{:>20}: {:7.4} seconds for {} loops'
        n=100
        print
        t = timeit.Timer(stmt="""
                counter = defaultdict(int)
                for k in LETTERS:
                    counter[k] += 1 
                """,
                setup="from collections import defaultdict; from __main__ import LETTERS")
        
        print fmt.format("defaultdict letters",t.timeit(n),n)
        t = timeit.Timer(stmt="""
                counter = defaultdict(int)
                for k in WORDS:
                    counter[k] += 1 
                """,
                setup="from collections import defaultdict; from __main__ import WORDS")
        
        print fmt.format("defaultdict words",t.timeit(n),n)
        print
        
        # setdefault
        t = timeit.Timer(stmt="""
                counter = {}
                for k in LETTERS:
                    counter[k]=counter.setdefault(k, 0)+1
                """,
                setup="from __main__ import LETTERS")
        print fmt.format("setdefault letters",t.timeit(n),n)
        t = timeit.Timer(stmt="""
                counter = {}
                for k in WORDS:
                    counter[k]=counter.setdefault(k, 0)+1
                """,
                setup="from __main__ import WORDS")
        print fmt.format("setdefault words",t.timeit(n),n)
        print
        
        # Counter
        t = timeit.Timer(stmt="c = Counter(LETTERS)",
                setup="from collections import Counter; from __main__ import LETTERS")
        
        print fmt.format("Counter letters",t.timeit(n),n)
        t = timeit.Timer(stmt="c = Counter(WORDS)",
                setup="from collections import Counter; from __main__ import WORDS")
        print fmt.format("Counter words",t.timeit(n),n)
        print
        
        # in
        t = timeit.Timer(stmt="""
                counter = {}
                for k in LETTERS:
                    if k in counter: counter[k]+=1
                    else: counter[k]=1   
                """,
                setup="from __main__ import LETTERS")
        print fmt.format("'in' letters",t.timeit(n),n)
        t = timeit.Timer(stmt="""
                counter = {}
                for k in WORDS:
                    if k in counter: counter[k]+=1
                    else: counter[k]=1   
                """,
                setup="from __main__ import WORDS")
        print fmt.format("'in' words",t.timeit(n),n)
        print
        
        # try
        t = timeit.Timer(stmt="""
                counter = {}
                for k in LETTERS:
                    try:
                        counter[k]+=1
                    except KeyError:
                        counter[k]=1     
                """,
                setup="from __main__ import LETTERS")
        print fmt.format("try letters",t.timeit(n),n)
        t = timeit.Timer(stmt="""
                counter = {}
                for k in WORDS:
                    try:
                        counter[k]+=1
                    except KeyError:
                        counter[k]=1             """,
                setup="from __main__ import WORDS")
        print fmt.format("try words",t.timeit(n),n)
        print "\n{:,} letters and {:,} words".format(len(list(LETTERS)),len(list(WORDS)))
        

        打印:

         defaultdict letters:   3.001 seconds for 100 loops
           defaultdict words:  0.8495 seconds for 100 loops
        
          setdefault letters:   4.839 seconds for 100 loops
            setdefault words:   0.946 seconds for 100 loops
        
             Counter letters:   7.335 seconds for 100 loops
               Counter words:   1.298 seconds for 100 loops
        
                'in' letters:   4.013 seconds for 100 loops
                  'in' words:  0.7275 seconds for 100 loops
        
                 try letters:   3.389 seconds for 100 loops
                   try words:   1.571 seconds for 100 loops
        
        175,176 letters and 26,630 words
        

        我个人很惊讶try except 是最快的方法之一。谁知道...

        【讨论】:

          【解决方案4】:

          我猜你只需要counter 模块。

          【讨论】:

            【解决方案5】:

            另一种方法是 try / except 子句:

            try: 
                filetypecounter[filetype] += 1
            except KeyError:
                filetypecounter[filetype] = 1
            

            如果你的文件类型比文件少,这个方法效率更高,因为你不需要检查filetype是否在filetypecounter中,而是假设是这种情况,只在filetypecounter中创建一个新条目如果不是。

            编辑:添加KeyError 以回应@delnan 的评论。

            【讨论】:

            • Bare except: 很糟糕,因为它捕获的异常多于合理的隐藏错误(在这种情况下,可能隐藏的错误示例是 filetypecounterfiletype 中的拼写错误,或包含无法递增的值的字典)。
            • 感谢@delnan,答案已适当修改。
            【解决方案6】:

            collections.Counter 类正是您(真正)需要的。

            【讨论】:

              【解决方案7】:

              我想你想要defaultdict:

              from collections import defaultdict
              
              d = defaultdict(lambda: 0)
              d['foo'] += 1
              # d['foo'] is now 1
              

              另一个想法是使用dict.setdefault:

              d = {}
              d.setdefault('foo', 0)  # won't override if 'foo' is already in d
              d['foo'] += 1
              

              【讨论】:

                猜你喜欢
                • 2011-02-05
                • 2013-09-10
                • 2015-11-02
                • 2021-04-23
                • 1970-01-01
                • 2017-06-24
                • 1970-01-01
                • 2023-03-13
                • 2021-07-25
                相关资源
                最近更新 更多