2

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

filetypecounter = {}

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

filetypecounter[filetype] +=1

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

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

有没有更蟒蛇的方式?

4

7 回答 7

3
from collections import defaultdict

filetypecounter = defaultdict(int)
filetypecounter[filetype] += 1

或者

from collections import Counter

filetypecounter = Counter()
filetypecounter.update([filetype])

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

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

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

于 2013-02-23T20:25:41.010 回答
2

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

于 2013-02-23T20:23:44.373 回答
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

这些方法有基准测试,defaultdict、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是最快的方法之一。谁知道...

于 2013-02-23T20:43:09.137 回答
1

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

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

如果您的文件类型比文件少,则此方法更有效,因为您无需检查是否filetype存在 in filetypecounter,而是假设是这种情况,并且仅在filetypecounter不存在时才创建新条目。

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

于 2013-02-23T20:25:00.050 回答
1

我想你需要的只是计数器模块。

于 2013-02-23T20:25:15.323 回答
1

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

于 2013-02-23T20:28:00.633 回答
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
于 2013-02-23T20:28:11.710 回答