2011-08-08 30 views
27

在Python最大出现的项目,我有一个列表:Python-发现列表中的

L = [1, 2, 45, 55, 5, 4, 4, 4, 4, 4, 4, 5456, 56, 6, 7, 67] 

我想,以确定发生的次数最多的项目。我能够解决它,但我需要最快的方式来做到这一点。我知道这是一个很好的Pythonic答案。

+4

你说你能够解决它。如果你可以提供你自己的解决方案作为起点,这对其他人也是有教育意义的。 –

回答

10

这里是一个defaultdict解决方案,将与Python版本2.5及以上的工作:

from collections import defaultdict 

L = [1,2,45,55,5,4,4,4,4,4,4,5456,56,6,7,67] 
d = defaultdict(int) 
for i in L: 
    d[i] += 1 
result = max(d.iteritems(), key=lambda x: x[1]) 
print result 
# (4, 6) 
# The number 4 occurs 6 times 

注意如果L = [1, 2, 45, 55, 5, 4, 4, 4, 4, 4, 4, 5456, 7, 7, 7, 7, 7, 56, 6, 7, 67] 则有六个4S和六个7S。然而,结果将是(4, 6),即六个4。

+2

很小,但'itemgetter(1)'可能比'lambda x:x [1]'结构在简单性和速度方面都更好。即请参阅http://docs.python.org/howto/sorting.html#operator-module-functions –

62
from collections import Counter 
most_common,num_most_common = Counter(L).most_common(1)[0] # 4, 6 times 

对于老版本的Python(< 2.7),你可以使用this receipe得到Counter类。

+1

有关详细信息,请参阅[Counter docs](http://docs.python.org/dev/library/collections.html#collections.Counter)。 – SiggyF

+0

这个解决方案非常优雅,但目前,另一个为我工作。 – zubinmehta

21

在你的问题中,你问最快的方法来做到这一点。正如一再被证明的那样,特别是在Python中,直觉并不是一个可靠的指南:你需要测量。

下面是几种不同的实现一个简单的测试:

import sys 
from collections import Counter, defaultdict 
from itertools import groupby 
from operator import itemgetter 
from timeit import timeit 

L = [1,2,45,55,5,4,4,4,4,4,4,5456,56,6,7,67] 

def max_occurrences_1a(seq=L): 
    "dict iteritems" 
    c = dict() 
    for item in seq: 
     c[item] = c.get(item, 0) + 1 
    return max(c.iteritems(), key=itemgetter(1)) 

def max_occurrences_1b(seq=L): 
    "dict items" 
    c = dict() 
    for item in seq: 
     c[item] = c.get(item, 0) + 1 
    return max(c.items(), key=itemgetter(1)) 

def max_occurrences_2(seq=L): 
    "defaultdict iteritems" 
    c = defaultdict(int) 
    for item in seq: 
     c[item] += 1 
    return max(c.iteritems(), key=itemgetter(1)) 

def max_occurrences_3a(seq=L): 
    "sort groupby generator expression" 
    return max(((k, sum(1 for i in g)) for k, g in groupby(sorted(seq))), key=itemgetter(1)) 

def max_occurrences_3b(seq=L): 
    "sort groupby list comprehension" 
    return max([(k, sum(1 for i in g)) for k, g in groupby(sorted(seq))], key=itemgetter(1)) 

def max_occurrences_4(seq=L): 
    "counter" 
    return Counter(L).most_common(1)[0] 

versions = [max_occurrences_1a, max_occurrences_1b, max_occurrences_2, max_occurrences_3a, max_occurrences_3b, max_occurrences_4] 

print sys.version, "\n" 

for vers in versions: 
    print vers.__doc__, vers(), timeit(vers, number=20000) 

我的机器上的结果:

2.7.2 (v2.7.2:8527427914a2, Jun 11 2011, 15:22:34) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] 

dict iteritems (4, 6) 0.202214956284 
dict items (4, 6) 0.208412885666 
defaultdict iteritems (4, 6) 0.221301078796 
sort groupby generator expression (4, 6) 0.383440971375 
sort groupby list comprehension (4, 6) 0.402786016464 
counter (4, 6) 0.564319133759 

所以看来Counter解决方案是不是最快的。而且,在这种情况下,至少,groupby更快。 defaultdict是好的,但你付出一点点为它的方便;使用dictget的速度稍快。

如果列表大得多,会发生什么?上面添加L *= 10000到测试和减少重复次数,以200:

dict iteritems (4, 60000) 10.3451900482 
dict items (4, 60000) 10.2988479137 
defaultdict iteritems (4, 60000) 5.52838587761 
sort groupby generator expression (4, 60000) 11.9538850784 
sort groupby list comprehension (4, 60000) 12.1327362061 
counter (4, 60000) 14.7495789528 

现在defaultdict是明显的赢家。因此,'get'方法的成本和inplace add的损失可能会相加(对生成的代码的检查仅作为练习)。

但是对于修改后的测试数据,唯一项目值的数量没有变化,所以推测dictdefaultdict比其他实现具有优势。那么,如果我们使用更大的列表,但会大幅增加独特项目的数量,会发生什么?与更换L的初始化:

LL = [1,2,45,55,5,4,4,4,4,4,4,5456,56,6,7,67] 
L = [] 
for i in xrange(1,10001): 
    L.extend(l * i for l in LL) 

dict iteritems (2520, 13) 17.9935798645 
dict items (2520, 13) 21.8974409103 
defaultdict iteritems (2520, 13) 16.8289561272 
sort groupby generator expression (2520, 13) 33.853593111 
sort groupby list comprehension (2520, 13) 36.1303369999 
counter (2520, 13) 22.626899004 

所以现在Counter明显快于groupby解决方案,但仍比iteritems版本dictdefaultdict慢。

这些例子的重点不是产生最佳解决方案。重点是经常没有一个最佳通用解决方案。另外还有其他性能标准。这些解决方案中的内存要求会有很大差异,并且随着输入大小的增加,内存需求可能成为算法选择的首要因素。底线:这一切都取决于你需要测量。

+0

这是一个梦幻般的答案,是任何解决方案的时间测试替代品的大量粉丝。谢谢Ned。 – Eugene

21

我很惊讶没有人提到的最简单的解决方案,max()用钥匙list.count

max(lst,key=lst.count) 

例子:

>>> lst = [1, 2, 45, 55, 5, 4, 4, 4, 4, 4, 4, 5456, 56, 6, 7, 67] 
>>> max(lst,key=lst.count) 
4 

这工作在Python 3或2,但要注意它只返回最频繁的项目,而不是频率。而且,在绘制(即联合最频繁项目)的情况下,仅返回单个项目。

我找到max()办法是约快两倍,Counter.most_common(1)

from collections import Counter 
from timeit import timeit 

def f1(lst): 
    return max(lst, key = lst.count) 

def f2(lst): 
    return Counter(lst).most_common(1) 

lst = range(100000) 

timeit(lambda: f1(lst), number = 1000) 
# 28.13 
timeit(lambda: f2(lst), number = 1000) 
# 59.01 
+0

非常好,优化的解决方案 – kkk

+0

我想解释一下max如何与'key ='一起工作, – Asara

0

我使用Python 3.5.2此功能得到groupby最好的结果从itertools模块:

from itertools import groupby 

a = [1, 2, 45, 55, 5, 4, 4, 4, 4, 4, 4, 5456, 56, 6, 7, 67] 

def occurrence(): 
    occurrence, num_times = 0, 0 
    for key, values in groupby(a, lambda x : x): 
     val = len(list(values)) 
     if val >= occurrence: 
      occurrence, num_times = key, val 
    return occurrence, num_times 

occurrence, num_times = occurrence() 
print("%d occurred %d times which is the highest number of times" % (occurrence, num_times)) 

输出:

4 occurred 6 times which is the highest number of times 

Tes与timeit模块的timeit

我用这个脚本为我的测试与number= 20000

from itertools import groupby 

def occurrence(): 
    a = [1, 2, 45, 55, 5, 4, 4, 4, 4, 4, 4, 5456, 56, 6, 7, 67] 
    occurrence, num_times = 0, 0 
    for key, values in groupby(a, lambda x : x): 
     val = len(list(values)) 
     if val >= occurrence: 
      occurrence, num_times = key, val 
    return occurrence, num_times 

if __name__ == '__main__': 
    from timeit import timeit 
    print(timeit("occurrence()", setup = "from __main__ import occurrence", number = 20000)) 

输出(最好的):

0.1893607140000313 
0

我想在另一个解决方案,看起来不错,是快扔短的名单。

def mc(seq=L): 
    "max/count" 
    max_element = max(seq, key=seq.count) 
    return (max_element, seq.count(max_element)) 

您可以基准本与斯内德Deily提供的代码,这将给你这些结果是最小的测试案例:

3.5.2 (default, Nov 7 2016, 11:31:36) 
[GCC 6.2.1 20160830] 

dict iteritems (4, 6) 0.2069783889998289 
dict items (4, 6) 0.20462976200065896 
defaultdict iteritems (4, 6) 0.2095775119996688 
sort groupby generator expression (4, 6) 0.4473949929997616 
sort groupby list comprehension (4, 6) 0.4367636879997008 
counter (4, 6) 0.3618192010007988 
max/count (4, 6) 0.20328268999946886 

但要注意,这是低效的,因而得到真的慢大列表!

0

以下是我提出的解决方案,如果字符串中有多个字符都具有最高的频率。

mystr = input("enter string: ") 
#define dictionary to store characters and their frequencies 
mydict = {} 
#get the unique characters 
unique_chars = sorted(set(mystr),key = mystr.index) 
#store the characters and their respective frequencies in the dictionary 
for c in unique_chars: 
    ctr = 0 
    for d in mystr: 
     if d != " " and d == c: 
      ctr = ctr + 1 
    mydict[c] = ctr 
print(mydict) 
#store the maximum frequency 
max_freq = max(mydict.values()) 
print("the highest frequency of occurence: ",max_freq) 
#print all characters with highest frequency 
print("the characters are:") 
for k,v in mydict.items(): 
    if v == max_freq: 
     print(k) 

输入: “你好人”

输出:

{'o': 2, 'p': 2, 'h': 1, ' ': 0, 'e': 3, 'l': 3} 

occurence的最高频率:3

字符是:

e 

l