【问题标题】:Sort list by frequency按频率排序列表
【发布时间】:2014-11-07 01:13:51
【问题描述】:

在 Python 中有什么方法可以按频率对列表进行排序吗?

例如,

[1,2,3,4,3,3,3,6,7,1,1,9,3,2]

上面的列表将按照其值出现的频率顺序进行排序以创建以下列表,其中频率最高的项目位于最前面:

[3,3,3,3,3,1,1,1,2,2,4,6,7,9]

【问题讨论】:

    标签: python list indexing frequency


    【解决方案1】:
    def orderByFrequency(list):
    
        listUniqueValues = np.unique(list)
        listQty = []
        listOrderedByFrequency = []
        
        for i in range(len(listUniqueValues)):
            listQty.append(list.count(listUniqueValues[i]))
        for i in range(len(listQty)):
            index_bigger = np.argmax(listQty)
            for j in range(listQty[index_bigger]):
                listOrderedByFrequency.append(listUniqueValues[index_bigger])
            listQty[index_bigger] = -1
        
        return listOrderedByFrequency
    
    #tests:
    print(orderByFrequency([1,2,3,4,3,3,3,6,7,1,1,9,3,2]))
    print(orderByFrequency([1,2,2]))
    print(orderByFrequency([1,2,1,2]))
    print(orderByFrequency([2,1,2,1]))
    print(orderByFrequency([3,3,3,4,4,4,4,1,5,5,5,5,5,2,2]))
    print(orderByFrequency([3,3,3,6,6,6,4,4,4,4,1,6,6,5,5,5,5,5,2,2]))
    print(orderByFrequency([10,20,30,30,30,40,40,50,50,50]))
    

    结果:

    [3, 3, 3, 3, 3, 1, 1, 1, 2, 2, 4, 6, 7, 9]
    [2, 2, 1]
    [1, 1, 2, 2]
    [1, 1, 2, 2]
    [5, 5, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3, 2, 2, 1]
    [5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 4, 4, 4, 4, 3, 3, 3, 2, 2, 1]
    [30, 30, 30, 50, 50, 50, 40, 40, 10, 20]
    

    【讨论】:

      【解决方案2】:

      如果您想使用双比较器。

      例如:按频率降序对列表进行排序,如果发生冲突,则较小的排在第一位。

      import collections 
      
      def frequency_sort(a):
          f = collections.Counter(a)
          a.sort(key = lambda x:(-f[x], x))
          return a
      

      【讨论】:

        【解决方案3】:

        您可以使用Counter 获取每个项目的计数,使用其most_common 方法按排序顺序获取它,然后使用列表推导再次展开

        >>> lst = [1,2,3,4,3,3,3,6,7,1,1,9,3,2]
        >>> 
        >>> from collections import Counter
        >>> [n for n,count in Counter(lst).most_common() for i in range(count)]
        [3, 3, 3, 3, 3, 1, 1, 1, 2, 2, 4, 6, 7, 9]
        

        【讨论】:

          【解决方案4】:

          练习这个是为了好玩。此解决方案使用较少的时间复杂度。

          from collections import defaultdict
          
          lis = [1,2,3,4,3,3,3,6,7,1,1,9,3,2]
          
          dic = defaultdict(int)
          for num in lis:
              dic[num] += 1
          
          s_list = sorted(dic, key=dic.__getitem__, reverse=True)
          
          new_list = []
          for num in s_list:
              for rep in range(dic[num]):
                  new_list.append(num)
          
          print(new_list)
          

          【讨论】:

            【解决方案5】:

            我认为这对collections.Counter 来说是一份不错的工作:

            counts = collections.Counter(lst)
            new_list = sorted(lst, key=lambda x: -counts[x])
            

            或者,您可以在没有 lambda 的情况下编写第二行:

            counts = collections.Counter(lst)
            new_list = sorted(lst, key=counts.get, reverse=True)
            

            如果您有多个具有相同频率的元素并且您关心这些元素保持分组,我们可以通过更改排序键来做到这一点,不仅包括计数,还包括

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

            【讨论】:

            • 如果你的列表中任意两个数字出现的频率相同,这可能行不通。
            【解决方案6】:

            您可以使用以下方法。它是用简单的python编写的。

            def frequencyIdentification(numArray):
            frequency = dict({});
            for i in numArray:
                if i in frequency.keys():
                        frequency[i]=frequency[i]+1;
                else:
                        frequency[i]=1;         
            return frequency;
            
            def sortArrayBasedOnFrequency(numArray):
                sortedNumArray = []
                frequency = frequencyIdentification(numArray);
                frequencyOrder = sorted(frequency, key=frequency.get);
                loop = 0;
                while len(frequencyOrder) > 0:
                    num = frequencyOrder.pop()
                    count = frequency[num];
                    loop = loop+1;
                    while count>0:
                        loop = loop+1;
                        sortedNumArray.append(num);
                        count=count-1;
                print("loop count");
                print(loop);
                return sortedNumArray;  
            
            a=[1, 2, 3, 4, 3, 3, 3, 6, 7, 1, 1, 9, 3, 2]
            print(a);
            print("sorted array based on frequency of the number"); 
            print(sortArrayBasedOnFrequency(a));
            

            【讨论】:

              【解决方案7】:
              from collections import Counter
              a = [2, 5, 2, 6, -1, 9999999, 5, 8, 8, 8]
              count = Counter(a)
              a = []
              while len(count) > 0:
                  c = count.most_common(1)
                  for i in range(c[0][1]):
                      a.append(c[0][0])
                  del count[c[0][0]]
              print(a)
              

              【讨论】:

              • 最好包含一些关于您的答案为何有效/是最佳解决方案的原因 - 以帮助 OP 和未来的访问者。
              【解决方案8】:
              l = [1,2,3,4,3,3,3,6,7,1,1,9,3,2]
              print sorted(l,key=l.count,reverse=True)
              
              [3, 3, 3, 3, 3, 1, 1, 1, 2, 2, 4, 6, 7, 9]
              

              【讨论】:

              • 这有一个缺点,每次调用 key 都是 O(n),而 collections.Counter 是 O(1),使用单个 O(n) 调用来构建 Counter (我没有投反对票,只是想指出效率差异)。
              • 这是一个单线器,但我猜它的算法复杂度是 O(n^2)。使用collections.Counter 可以避免为列表中的每个项目计算每个项目的出现次数。
              猜你喜欢
              • 1970-01-01
              • 2021-01-20
              • 1970-01-01
              • 2016-08-27
              • 1970-01-01
              • 2013-12-28
              • 1970-01-01
              相关资源
              最近更新 更多