在Python中使用循环计算字典中元素的有效方法

在Python中使用循环计算字典中元素的有效方法,python,performance,dictionary,coding-style,Python,Performance,Dictionary,Coding Style,我有一个价值清单。我希望在循环期间计算每个类的元素数(即1,2,3,4,5) 我希望得到这个结果 Out[344]: {1: 6, 2: 5, 3: 3, 4: 1, 5: 4} 尝试收集。计数器: >>> from collections import Counter >>> Counter([1,1,1,1,1,1,2,3,2,2,2,2,3,3,4,5,5,5,5]) Counter({1: 6, 2: 5, 5: 4, 3: 3,

我有一个价值清单。我希望在循环期间计算每个类的元素数(即1,2,3,4,5)

我希望得到这个结果

Out[344]: {1: 6, 2: 5, 3: 3, 4: 1, 5: 4}

尝试收集。计数器:

   >>> from collections import Counter
   >>> Counter([1,1,1,1,1,1,2,3,2,2,2,2,3,3,4,5,5,5,5])
   Counter({1: 6, 2: 5, 5: 4, 3: 3, 4: 1})
在您的代码中,您基本上可以用
计数器替换
mydict
,然后写入

mydict[index] += 1
而不是

mydict[index] = +1
要更正代码:

mydict[index] = +1
应该是:

mydict[index] = mydict.setdefault(index, 0) + 1

您的代码指定1作为每个键的值。将mydict[index]=+1替换为mylist.count(index)

这应该起作用:

mylist = [1,1,1,1,1,1,2,3,2,2,2,2,3,3,4,5,5,5,5]
mydict = dict()
for index in mylist:
    mydict[index] = mylist.count(index)
mydict

对于较小的示例,由于元素的多样性有限,您可以使用集合和dict理解:

>>> mylist = [1,1,1,1,1,1,2,3,2,2,2,2,3,3,4,5,5,5,5]
>>> {k:mylist.count(k) for k in set(mylist)}
{1: 6, 2: 5, 3: 3, 4: 1, 5: 4}
要分解它,
set(mylist)
uniquified列表并使其更加紧凑:

>>> set(mylist)
set([1, 2, 3, 4, 5])
然后,字典理解逐步遍历唯一值并从列表中设置计数

这也比使用计数器和使用setdefault快得多:

from __future__ import print_function
from collections import Counter
from collections import defaultdict
import random

mylist=[1,1,1,1,1,1,2,3,2,2,2,2,3,3,4,5,5,5,5]*10

def s1(mylist):
    return {k:mylist.count(k) for k in set(mylist)}

def s2(mlist):
    return Counter(mylist)

def s3(mylist):
    mydict=dict()
    for index in mylist:
        mydict[index] = mydict.setdefault(index, 0) + 1
    return mydict   

def s4(mylist):
    mydict={}.fromkeys(mylist,0)
    for k in mydict:
        mydict[k]=mylist.count(k)    
    return mydict    

def s5(mylist):
    mydict={}
    for k in mylist:
        mydict[k]=mydict.get(k,0)+1
    return mydict     

def s6(mylist):
    mydict=defaultdict(int)
    for i in mylist:
        mydict[i] += 1
    return mydict       

def s7(mylist):
    mydict={}.fromkeys(mylist,0)
    for e in mylist:
        mydict[e]+=1    
    return mydict    

if __name__ == '__main__':   
    import timeit 
    n=1000000
    print(timeit.timeit("s1(mylist)", setup="from __main__ import s1, mylist",number=n))
    print(timeit.timeit("s2(mylist)", setup="from __main__ import s2, mylist, Counter",number=n))
    print(timeit.timeit("s3(mylist)", setup="from __main__ import s3, mylist",number=n))
    print(timeit.timeit("s4(mylist)", setup="from __main__ import s4, mylist",number=n))
    print(timeit.timeit("s5(mylist)", setup="from __main__ import s5, mylist",number=n))
    print(timeit.timeit("s6(mylist)", setup="from __main__ import s6, mylist, defaultdict",number=n))
    print(timeit.timeit("s7(mylist)", setup="from __main__ import s7, mylist",number=n))
在我的打印机器上(Python 3):

对于较大的列表,如1000万个整数,以及更多不同的元素(1500个随机整数),请在循环中使用defaultdict或fromkeys:

from __future__ import print_function
from collections import Counter
from collections import defaultdict
import random

mylist = [random.randint(0,1500) for _ in range(10000000)]

def s1(mylist):
    return {k:mylist.count(k) for k in set(mylist)}

def s2(mlist):
    return Counter(mylist)

def s3(mylist):
    mydict=dict()
    for index in mylist:
        mydict[index] = mydict.setdefault(index, 0) + 1
    return mydict   

def s4(mylist):
    mydict={}.fromkeys(mylist,0)
    for k in mydict:
        mydict[k]=mylist.count(k)    
    return mydict    

def s5(mylist):
    mydict={}
    for k in mylist:
        mydict[k]=mydict.get(k,0)+1
    return mydict     

def s6(mylist):
    mydict=defaultdict(int)
    for i in mylist:
        mydict[i] += 1
    return mydict       

def s7(mylist):
    mydict={}.fromkeys(mylist,0)
    for e in mylist:
        mydict[e]+=1    
    return mydict    

if __name__ == '__main__':   
    import timeit 
    n=1
    print(timeit.timeit("s1(mylist)", setup="from __main__ import s1, mylist",number=n))
    print(timeit.timeit("s2(mylist)", setup="from __main__ import s2, mylist, Counter",number=n))
    print(timeit.timeit("s3(mylist)", setup="from __main__ import s3, mylist",number=n))
    print(timeit.timeit("s4(mylist)", setup="from __main__ import s4, mylist",number=n))
    print(timeit.timeit("s5(mylist)", setup="from __main__ import s5, mylist",number=n))
    print(timeit.timeit("s6(mylist)", setup="from __main__ import s6, mylist, defaultdict",number=n))
    print(timeit.timeit("s7(mylist)", setup="from __main__ import s7, mylist",number=n))
印刷品:

2825.2697427899984              # set and dict comprehension 
42.607481333994656              # Counter 
22.77713537499949               # setdefault 
2853.11187016801                # fromkeys / count 
23.241977066005347              # dict.get 
15.023175164998975              # defaultdict 
18.28165417900891               # fromkeys / loop

您可以看到,与其他解决方案相比,在大列表中使用次数适中的
count
解决方案将遭受严重/灾难性的影响

setdefault方法的一个变体是
collections.defaultdict
。这要快一点

def foo(mylist):
    d=defaultdict(int)
    for i in mylist:
        d[i] += 1
    return d
itertools.groupBy
提供了另一个选项。它的速度大约与计数器的速度相同(至少在2.7上)

然而,在处理OP在评论中提到的32Gb数据时,这个小测试列表上的时间测试可能不同


我在word count案例中运行了其中几个选项

在那里,OP使用计数器,并试图通过使用多处理来加快速度。对于1.2Mb的文本文件,使用
defaultdict
的计数器速度很快,取0.2秒。对输出进行排序以获得前40个单词所用的时间与计数本身所用的时间一样长

计数器
3.2
上稍慢,在
2.7
上则慢得多。这是因为
3.2
是一个编译版本(
.so
文件)


但是当处理一个大的列表时,使用mylist.count的计数器停止工作;差不多200秒。它必须多次搜索这个大列表,一次收集密钥,然后在计数时为每个密钥搜索一次。

收集。计数器
,在您需要的代码中:
mydict[index]+=1
我可以问一个例子吗?提前感谢
收藏。计数器(mylist)
就完成了。(好吧,除了导入
集合
,您还需要对计数执行任何操作,但是
集合。计数器(mylist)
是整个“计数”阶段。)也许@GrijeshChauhan是的,我只是想指出OP错误地使用了运算符。(虽然它会引发
KeyError
)谢谢,但我很抱歉,因为我需要在循环中找到一种方法。列表就是一个例子,因为我有32 GB的数据要在循环中运行/如果你在32 GB的项上有一个迭代器,
集合。计数器
的工作原理与列表相同。谢谢。我得到了你的例子{1:7,2:6,3:4,4:2,5:5}。最好的方法是mydict[index]=mydict.get(index,0)+1@Gianni哦,我刚刚更正,我是新的Python学习者,所以我发布了一个简单的答案。我想说最好的方法是我自己使用一个计数器,因为它很简单,但这种方法是有效的。@user2387370如果这样行得通,我会很高兴,因为我刚刚开始使用Python:)嘿@Gianni你注意到你的表达式
mydict[index]=+1
只是
mydict[index]=1
所以你总是得到
1
的值:)。你可能被
mydict[index]+=1拼写错误,但我怀疑这是一个关键的例外,因为最初在
mydict[index]上没有值
请阅读Ashwini在您的问题中对我的第二条评论。有人知道为什么Cunter类比默认的dict类慢得多吗?
2825.2697427899984              # set and dict comprehension 
42.607481333994656              # Counter 
22.77713537499949               # setdefault 
2853.11187016801                # fromkeys / count 
23.241977066005347              # dict.get 
15.023175164998975              # defaultdict 
18.28165417900891               # fromkeys / loop
def foo(mylist):
    d=defaultdict(int)
    for i in mylist:
        d[i] += 1
    return d
{x[0]:len(list(x[1])) for x in itertools.groupby(sorted(mylist))}