在python中,如何按元素的频率对列表进行排序
Posted
技术标签:
【中文标题】在python中,如何按元素的频率对列表进行排序【英文标题】:In python, how to sort list by frequency of elements 【发布时间】:2014-10-10 09:07:24 【问题描述】:我有一个元素列表:[ 3, 3, 6, 6, 6, 5, 5, 8 ]
,需要按元素的频率对其进行排序以获得此:[ 6, 6, 6, 3, 3, 5, 5, 8 ]
的几个元素具有相同的频率,按值对它们进行排序。你能找到比这更短的方法吗?
import collections
from operator import itemgetter, attrgetter
def freq_sort(arr):
counter=collections.Counter(arr)
com = sorted(counter.most_common(), key=itemgetter(1,0), reverse=True)
com = map(lambda x: [x[0]] * x[1], com)
return [item for sublist in com for item in sublist]
【问题讨论】:
属于 codereview.stackexchance。 定义“更短”。 Darth Kotik 提出的答案在字符方面更短,但它不必要地为列表中的每个唯一元素执行一个额外的循环。附带说明一下,如果在具有可变元素的列表中使用给定的解决方案,则会产生问题。 【参考方案1】:试试这个
>>> old_list = [ 3, 3, 6, 6, 6, 5, 5, 8 ]
new_list = sorted(old_list, key = old_list.count, reverse=True)
>>> new_list
[6, 6, 6, 3, 3, 5, 5, 8]
【讨论】:
当计数相等时,这不会按值排序。也有 list.count 作为关键功能不是很有效(使排序 O(N*N)) 您能否进行一些基准测试以显示执行时间与相关解决方案的比较? 如果old_list
的长度足够,你会想记住old_list.count
。【参考方案2】:
collections.Counter 方法 most_common() 几乎可以满足您的需求。它返回按频率排序的对(值,频率)。您还需要按值对列表进行排序;该方法不能保证它(规范说当频率相同时,值的顺序是任意的)。所以我们必须将它传递给 sorted() 函数。
代码如下:
from collections import Counter
l = [ 3, 3, 6, 6, 6, 5, 5, 8 ]
c = Counter(l)
sc = sorted(c.most_common(), key=lambda x: (-x[1], x[0])) # sorting happens here
sl = [([v] * n) for (v, n) in sc]
ss = sum(sl, [])
print(ss)
与其他方法相比,该方法的优势在于它只在时间上运行 O(m log m),其中 m 是 l 中的多个不同值。其他方法将在时间 O(n log n) 中运行,其中 n 是长度 o l,它总是大于或等于不同值的数量。您基本上将使用桶排序算法。
【讨论】:
【参考方案3】:这在行数方面有点短,首先按计数排序,然后按值排序:
import collections
arr = [ 3, 3, 6, 6, 6, 5, 5, 8 ]
counter = collections.Counter(arr)
sorted( arr, key=lambda x: (counter[x], x), reverse=True )
【讨论】:
应该是(counter[x], -x)
才能得到正确的顺序【参考方案4】:
执行两种排序通常比 lambda 函数的额外开销要快。这是因为 Python 的排序是稳定的
>>> from collections import Counter
>>> L = [ 3, 3, 6, 6, 6, 5, 5, 8 ]
>>> c = Counter(L)
>>> sorted(sorted(L), key=c.get, reverse=True)
[6, 6, 6, 3, 3, 5, 5, 8]
第二次排序非常快,因为数据现在已经部分排序,这是 timsort 擅长的。
【讨论】:
以上是关于在python中,如何按元素的频率对列表进行排序的主要内容,如果未能解决你的问题,请参考以下文章