在Python中使用循环计算字典中元素的有效方法
我有一个价值清单。我希望在循环期间计算每个类的元素数(即1,2,3,4,5) 我希望得到这个结果在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,
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))}