【问题标题】:python How do you sort list by occurrence with out removing elements from the list?python 如何在不从列表中删除元素的情况下按出现次数对列表进行排序?
【发布时间】:2017-07-12 16:30:06
【问题描述】:

只是想知道如何在 python 2.7 中按频率/出现对列表进行排序,如果 2 个元素出现的次数相同,那么在原始列表中首先出现的元素在新列表中的另一个元素之前。

例如:

list = [5,6,8,9,8,8,3,4,4,6,6]
sorted_list = [6,6,6,8,8,8,4,4,5,9,3]

知道为什么该解决方案不适用于 [1,3,3,3,2,2,2,1,1]。输出为 [3,3,3,2,2,2,1 ,1,1] 但正确的输出是 [1,1,1,3,3,3,2,2,2] 再次感谢

【问题讨论】:

  • 我刚刚发布了一个答案,但我想知道为什么在您的预期输出中 8 在 6 之前,即使 6 在原始列表中首先出现?
  • 对不起,我把想要的输出搞砸了,我现在改了,谢谢
  • MSeifert (& my) 的代码给出了[1,3,3,3,2,2,2,1,1] 的正确答案,我认为 Mureinik 的更新版本也是如此,但我还没有测试过。

标签: python python-2.7 list sorting frequency


【解决方案1】:

您可以使用collections 中的Counter 类作为排序键。由于您可能有多个出现次数相同的元素,因此您可以将值本身用作辅助排序键,以便将相同的元素组合在一起:

>>> from collections import Counter
>>> lst = [5,6,8,9,8,8,3,4,4,6,6] 
>>> c = Counter(lst)
>>> sorted(lst, key = lambda x : (c[x], x), reverse = True)
[8, 8, 8, 6, 6, 6, 4, 4, 9, 5, 3]

编辑: 正如 MSeifert 评论的那样,应该按照第一次出现的顺序来打破关系,而不是元素的值。这可以使用原始列表中的index 函数来完成:

>>> sorted(lst, key = lambda x : (-1 * c[x], lst.index(x)))
[6, 6, 6, 8, 8, 8, 4, 4, 5, 9, 3]

【讨论】:

  • 二级排序键在我心中始终占有一席之地
  • 也就是说,我想你忘了定义c
  • @Jean-FrançoisFabre 是的-尝试了几次,直到我做对了,并尝试仅复制粘贴相关行。显然,我忘记了一个 :-) 已编辑并修复,感谢您的注意!
  • 但是问题希望具有相同出现次数的项目出现在“首次出现的顺序”中,而不是按它们的“值”。请注意预期输出中的 5,9,3 与您的输出中的 9, 5, 3。
  • 但是,由于索引每个列表项,新版本为 O(n²)。
【解决方案2】:

要进行这种排序,您需要找到第一个索引和每个项目的计数。我将使用一个函数来完成这两个任务,但还有其他方法:

def count_and_first_index(it):
    dct_counts = {}
    dct_first = {}
    for idx, item in enumerate(it):
        if item in dct_counts:
            dct_counts[item] += 1
        else:
            dct_counts[item] = 1
            dct_first[item] = idx

    return dct_counts, dct_first

然后使用key-argument 进行简单排序:

>>> lst = [5,6,8,9,8,8,3,4,4,6,6]

>>> counts, firstidx = count_and_first_index(lst)

>>> sorted(lst, key=lambda x: (counts[x], -firstidx[x]), reverse=True)
[6, 6, 6, 8, 8, 8, 4, 4, 5, 9, 3]

我否定了index,因为它的排序是颠倒的,你首先想要第一个项目。但是您也可以否定counts 并删除reverse:

>>> sorted(lst, key=lambda x: (-counts[x], firstidx[x]))
[6, 6, 6, 8, 8, 8, 4, 4, 5, 9, 3]

【讨论】:

  • 我猜你也可以使用sorted(lst, key=lambda x:(-lst.count(x), lst.index(x))),尽管它在计数和索引方面效率很低(O(n^2) 而不是 O(n))。
  • @PM2Ring 是的,这就是为什么我写了“我将使用一个函数来做这两件事,但还有其他方法”。我觉得使用O(n**2) 方法会宠坏我(它还会遍历列表两次,因为count 和index 是单独的操作!)当O(n) 方法(短且)可能时。
  • 嗯,2O(n²) 仍然是 O(n²) :)
  • @PM2Ring 是的,但这并没有让我感觉更好。但是,我建议您也将您的建议作为另一个答案发布。它非常短(代码方面),对于非常短的迭代,count 和 index 非常快。有些人喜欢这样:)
  • 我想我可以发布一个单独的答案,但这主要是解释为什么你不应该这样做,除非列表真的很小,因为O(n²) 问题,他们应该真正使用您的解决方案。 :)
猜你喜欢
  • 2017-06-20
  • 2022-01-23
  • 1970-01-01
  • 1970-01-01
  • 2020-08-28
  • 1970-01-01
  • 2016-09-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多