按频率对列表进行排序

时间:2020-10-05 07:35:06

标签: python python-3.x list sorting

我想按列表的降序对列表进行排序。如果两个值的频率相同,那么我也希望这两个值的降序。

例如,

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

我希望我的结果成为

[4,4,4,4,4,4,3,3,3,3,3,5,5,5,2,2,2,1,1].

如果我使用

sorted(mylist,key = mylist.count,reverse = True)

我会得到

[4,4,4,4,4,4,3,3,3,3,3,2,2,2,5,5,5,1,1];

我尝试过

 sorted(mylist,key = lambda x:(mylist.count,-x),reverse = True)

但是我认为出了点问题,它只会给我结果:

[1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5].

所以我的问题是如何获得想要的结果以及为什么会得到结果

[1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5]

如果我使用

sorted(mylist,key = lambda x:(mylist.count,-x),reverse = True)

3 个答案:

答案 0 :(得分:1)

使用计数器获取频率,然后按其给出的频率排序:

from collections import Counter

def sorted_by_frequency(arr):
    counts = Counter(arr)

    # secondarily sort by value
    arr2 = sorted(arr, reverse=True)

    # primarily sort by frequency
    return sorted(arr2, key=counts.get, reverse=True)

# Usage:
>>> sorted_by_frequency([1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 5, 5, 5, 4, 4, 4, 4, 4, 4])
[4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 5, 5, 5, 2, 2, 2, 1, 1]

答案 1 :(得分:0)

您可以尝试:

from collections import Counter

counts = Counter(mylist)
new_list = sorted(mylist, key=lambda x: (counts[x], x), reverse=True)

答案 2 :(得分:0)

为什么

sorted(mylist, key=lambda x: (mylist.count, -x), reverse=True)

错了吗?

它比较键,例如,两个值31变成对(mylist.count, -3)(mylist.count, -1),比较将是(mylist.count, -3) < (mylist.count, -1)

所以显而易见的错误是,这些对没有预期的数字频率。相反,它们具有该功能。而且功能不少于它本身。

但是我发现有趣的是,接下来会发生什么。该对比较如何工作?您可能会认为(a, b) < (c, d)等效于(a < c) or (a == c and b < d)。事实并非如此。因为这将评估mylist.count < mylist.count,然后您将陷入TypeError的崩溃。元组之间进行比较的实际方式是通过first finding a difference,这是通过检查平等来完成的。并且mylist.count == mylist.count不仅不会崩溃,而且会返回True。因此,元组比较然后转到下一个索引,在该索引中将找到-3-1

所以本质上您实际上只是在做

sorted(mylist, key=lambda x: -x, reverse=True)

以及否定和reverse=True相互抵消,因此您获得与

相同的结果
sorted(mylist, key=lambda x: x)

或者只是

sorted(mylist)

现在如何正确处理?一种方法是调用函数(并删除否定符):

result = sorted(mylist, key=lambda x: (mylist.count(x), x), reverse=True)

或否定频率和值,而不是reverse=True

result = sorted(mylist, key=lambda x: (-mylist.count(x), -x))

另一种方法是利用排序的稳定性,并使用两个更简单的排序(甚至可能比另一个复杂的排序要快):

result = sorted(mylist, reverse=True)
result.sort(key=mylist.count, reverse=True)

请注意,在这里我们不必自己调用mylist.count,因为它是为我们调用的密钥。就像您的“ lambda函数”确实被调用一样(只是不是其结果内部的函数)。另外请注意,我使用sorted,然后使用原位sort-毫无意义地创建另一个列表,并且会产生与之相关的费用。

尽管在所有情况下,对于长列表,使用collections.Counter代替mylist.count会更有效,因为后者会使解取O(n 2 ),而不是O(n log n)。