2017-02-22 196 views
3

只是想知道如何按python 2.7中的频率/出现次序对列表进行排序,如果2个元素出现的次数相同,则原始列表中第一个出现的元素位于新列表中其他元素的前面。python如何从列表中删除元素的排序列表?

例如:

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] .The输出为[3工作, 3,3,2,2,2,1,1,1]但正确的输出是[1,1,1,3,3,3,2,2,2] 再次感谢

+2

我刚刚发布了一个答案,但我不知道为什么在你的预期产出的'8'是前'6'即使'6'第一的发生原始列表? – MSeifert

+0

对不起,我搞砸了所需的输出我现在改变了,谢谢 – jonny

+0

MSeifert的(&我的)代码给出了[1,3,3,3,2,2,2,1,1]'的正确答案,我假设Mureinik的更新版本也是如此,但我还没有测试过它。 –

回答

2

您可以使用作为排序键的Counter类从collections。由于可能有多个元件用相同的出现次数,则可以使用该值本身作为二次分选键,以便相同的元件被分组在一起:

>>> 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] 
+0

二级分拣键总是在我心中有一个特别的地方 –

+0

说,我认为你忘了定义'c' –

+0

@ Jean-FrançoisFabrey - 进行了几次尝试,直到我找对了,并试图只复制粘贴相关线路。显然,我忘了一个:-)编辑和修复,感谢您注意! – Mureinik

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] 
+1

我想你也可以做'排序(lst,key = lambda x:( - lst.count(x),lst.index(x)))',尽管这样做效率并不高, (O(n^2)而不是O(n))。 –

+0

@ PM2Ring是的,这就是为什么我写了“我将使用一个函数来完成这两个任务,但也有其他方法”。我觉得当'O(n)'方法是(O(n)2)方法时(它也会遍历列表两次,因为count和索引是单独的操作)简短和)可能。 – MSeifert

+0

那么,2O(n²)仍然是O(n²):) –