如何在python列表中找到所有最常见的元素(如果匹配,按字母顺序排列)



如何在python列表中找到所有最常见的元素(如果匹配,按字母顺序排列(假设你有一个清单'l=['b'、'b','a'、'a','c']'输出应该是"a 2,b 2"就时间复杂性而言,我需要一个有效的解决方案。非常感谢。

这里有一个可能的解决方案(如评论中所讨论的(:

from collections import Counter
lst = # your list of characters
c = Counter(lst) # O(n)
largest = max(counts.values()) # O(n)
largest_with_ties = [k for k, v in counts.items() if v == largest] # O(n)
result = sorted(largest_with_ties)

现在,sorted(largest_with_ties)的复杂性是什么?可以说它是O(nlogn((因为可能有n/2个平局(。但是,largest_with_ties中的字符数不能与lst中的元素数一样多。这是因为与可能的int数量相比,字符数量要少得多。换句话说,lst可能包含10^20个数字(只是一个例子(。但是largest_with_ties只能包含不同的字符,并且可以用UTF8表示的字符数(例如(被限制为或多或少10^6。因此,从技术上讲,最后一次运算的复杂性是O(1(。一般来说,我们可以说它是O(nlogn(,但上限是O(10^6log10^6(。

我想看看我是否能让@riccardo-bucco的回答更快(我做不到(,但我会向你展示一个基本上与我认为可能更快的速度相同的替代方案。

需要明确的是,我觉得最好的答案来自@riccardo_bucco,因为它更容易理解,速度也一样快。使用它。

我希望不必扫描计数器两次就可以重置最大的with_ties列表,但事实并非如此。

def jonsg(data_in):
largest_with_ties = [(None, 0)]
for item in collections.Counter(data_in).items():
diff = item[1] - largest_with_ties[0][1]
if diff < 0:
continue
if diff > 0:
largest_with_ties.clear()
largest_with_ties.append(item)
return sorted(largest_with_ties)

测试时间,我将使用";《莎士比亚全集》;来自古腾堡计划。你可以在这里(5.5米(:https://www.gutenberg.org/files/100/100-0.txt

请注意,我稍微修改了Riccardo Bucco的答案,返回了一个元组,并不是说它对性能有影响。

import timeit
setup = """
import collections
#data_in = ['b', 'b', 'a', 'a', 'c']
with open("shakespeare.txt", "r", encoding="utf-8") as file_in:
data_in = [word.strip().lower() for line in file_in for word in line.split()]
def riccardo_bucco(data_in):
counts = collections.Counter(data_in) # O(n)
largest = max(counts.values()) # O(n)
largest_with_ties = [item for item in counts.items() if item[1] == largest] # O(n)
return sorted(largest_with_ties)
def jonsg(data_in):
largest_with_ties = [(None, 0)]
for item in collections.Counter(data_in).items():
diff = item[1] - largest_with_ties[0][1]
if diff < 0:
continue
if diff > 0:
largest_with_ties.clear()
largest_with_ties.append(item)
return sorted(largest_with_ties)
"""

现在我们可以运行:

print(f"riccardo_bucco: {timeit.timeit('riccardo_bucco(data_in)', setup=setup, number=100)}")
print(f"jonsg         : {timeit.timeit('jonsg(data_in)', setup=setup, number=100)}")

给出如下结果:

riccardo_bucco: 10.59
jonsg         : 10.55

向我暗示他们的表现同样好(或差(。请随意将其扩展到其他尝试中。

仅供参考:实际最常见的是:('the', 30087)

如果要使用单个字符进行测试,则可以通过:设置data_in

data_in = [char.lower() for char in file_in.read() if char.strip()]

在这种情况下,最常见的是[('e', 482212)]

但这样做并不会从根本上改变这些解决方案的相对性能。

使用您的代码和计数器,我们得到以下内容:

from collections import Counter
def most_frequent(List):
occurence_count = Counter(List)
return occurence_count.most_common()
l = ['b', 'b', 'b', 'a', 'a', 'c']

print(sorted(most_frequent(l)))

我们得到的输出:

[('a', 2), ('b', 3), ('c', 1)]

使用sorted,我们会自动按字母表对项目进行排序。

您可以使用以下代码仔细检查其按字母顺序排序:

tuplesInList = (most_frequent(l))
#to sort tuples within lists we use an anonymous function(lambda)
def sort_tuple_vals(my_tup):
my_tup.sort(key=lambda x:x[0])
return my_tup

这将根据元组中的第一个元素对元组进行排序

print(sort_tuple_vals(tuplesInList))

获取输出

[('a', 2), ('b', 3), ('c', 1)]

如果您想按出现次数排序,而不是按字母顺序排序,那么在平局的情况下按字母顺序进行排序,下面的代码应该可以工作。我们首先根据lambda x:x[1]的出现次数对元组进行排序

tuplesInList = (most_frequent(l))
#to sort tuples within lists we use an anonymous function(lambda)
def sortTupsbyOccurance(my_tup):
my_tup.sort(key=lambda x:x[1])
print(my_tup)
return my_tup
tuple=(sortTupsbyOccurance(tuplesInList))
print(tuple)

从初始列表l=['b','b'、'b'和'a','a'、'a'和'c']中,我们得到输出:

[('c', 1), ('b', 3), ('a', 3)]

使用这个,我相信我们可以解决按字母排序的问题。如果在位置n的第二个值处的元组等于在位置n+1处的元组的第二值,我们注意到等式,并使用这些值转到下一个if语句。因为我们从0号位开始,我们肯定不会跳过任何潜在的比赛。

#set the n value for  range 0, n to the number of tuple entries in the list.
for n in range(0,2):
if tuple[n][1]==tuple[n+1][1]:
print("there is an equality")
var1=str(tuple[n][0])
var2= str(tuple[n+1][0])
if var1 > var2:
print(var1, var2)
print("this is true")
# if tuple at position n's 1st value (alphabeticaly) is greater than tuple n+1's first value then we switch them.

tuple[n], tuple[n+1] = tuple[n+1], tuple[n]
print(tuple)

从具有3〃的初始列表l;a";s和3〃;b";我们得到的输出是:

[('c', 1), ('a', 3), ('b', 3)]

相关内容

最新更新