如果值不存在,在字典中设置值?

时间:2013-02-23 20:21:43

标签: python

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

filetypecounter = {}

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

filetypecounter[filetype] +=1

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

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

有更多的pythonic方式吗?

7 个答案:

答案 0 :(得分:3)

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

实际上,这个和其他建议只是同一个主题的变化。我会用Counter。

答案 1 :(得分:2)

对于Python 2.7及更高版本,您想要的是collections.defaultdictcollections.Counter

答案 2 :(得分:2)

在这组答案中很好地使用了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是最快的方法之一。谁知道...

答案 3 :(得分:1)

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

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

如果您的文件类型少于文件,则此方法效率更高,因为您可以假设情况只是创建新条目,而不是不必要地检查filetype是否在filetypecounter中。在filetypecounter中,如果不是。

修改:添加KeyError以回复@delnan的评论。

答案 4 :(得分:1)

我猜你所需要的只是counter模块。

答案 5 :(得分:1)

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

答案 6 :(得分:0)

我想你想要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