【问题标题】:Python Sort string by frequency - cannot sort with sorted() functionPython 按频率排序字符串 - 无法使用 sorted() 函数排序
【发布时间】:2017-11-08 21:39:14
【问题描述】:

我在按频率对简单字符串进行排序时遇到问题(我得到一个字符串作为输入,我需要按降序将排序后的字符串作为输出返回)。 举个例子(原词有4个e、2个s、1个t、1个r、1个d,所以排序):

In [1]: frequency_sort("treeseeds")
Out [1]: "eeeesstrd"

Stack Overflow 上的大多数解决方案都表明我应该使用 sorted() 函数来获取结果,但是,它似乎只适用于某些情况。

我创建了两个应该可以工作的函数,但它们似乎都不能用我的特定输入来解决问题(见下文)。

第一个函数:

def frequency_sort(s):
    s_sorted = sorted(s, key=s.count, reverse=True)
    s_sorted = ''.join(c for c in s_sorted)
    return s_sorted

第二个功能:

import collections
def frequency_sort_with_counter(s):
    counter = collections.Counter(s)
    s_sorted = sorted(s, key=counter.get, reverse=True)
    s_sorted = ''.join(c for c in s_sorted)
    return s_sorted

使用这两个函数,我的输出如下所示:

第一个输出没问题:

In [1]: frequency_sort("loveleee")
Out [1]: "eeeellov"

第二个输出没那么多

In [2]: frequency_sort("loveleel")
Out [2]: "leleelov"

第三个输出完全乱七八糟:

In [3]: frequency_sort("oloveleelo")
Out [3]: "oloeleelov"

可能出了什么问题?它是否以某种方式与“o”和“l”字符相关联?还是我只是错过了什么?

【问题讨论】:

标签: python string sorting frequency


【解决方案1】:

在多个字符具有相同频率的字符串中,您提出的算法无法区分出现次数相同的字符。您可以通过使用频率和字符本身的元组进行排序来解决这个问题;例如

In [7]: def frequency_sort(s):
        s_sorted = sorted(s, key=lambda c: (s.count(c), c), reverse=True)
        s_sorted = ''.join(c for c in s_sorted)
        return s_sorted
   ...: 

In [8]: frequency_sort("loveleel")
Out[8]: 'llleeevo'

【讨论】:

    【解决方案2】:

    在您的第三种情况下,三个字母的计数相同,这就是它们放在一起的原因,您可以先对其进行排序(按字母表),然后按频率排序,将字母排列如下:

    s_sorted = ''.join(sorted(sorted(s), key=lambda x: s.count(x), reverse=True))
    

    输出:

    eeellloooav
    

    或者你可以反转它:

    s_sorted = ''.join(sorted(sorted(s, reverse=True), key=lambda x: s.count(x), reverse=True))
    

    输出:

    ooollleeeva
    

    【讨论】:

      【解决方案3】:

      问题在于sortsorted 是稳定的排序。因此,如果两个值“相等”(在本例中为 key(item1) == key(item2)),它们将按照与 sort 之前相同的顺序出现。

      例如,在您的最后一个案例中,您有:

      >>> from collections import Counter
      
      >>> Counter("oloveleelo")
      Counter({'e': 3, 'l': 3, 'o': 3, 'v': 1})
      

      所以'e''l''o' 具有相同的key,因此它们将像原来一样出现:"oloeleelo",然后出现唯一具有不同计数的字符:@987654332 @。

      如果你不关心数量相等的元素的顺序(只是它们按字符分组)你甚至不需要sorted,只需将Counter.most_common的结果展平即可:

      >>> ''.join([item for item, cnt in Counter("oloveleelo").most_common() for _ in range(cnt)])
      'llleeeooov'
      >>> ''.join([item for item, cnt in Counter("loveleel").most_common() for _ in range(cnt)])
      'eeelllov'
      >>> ''.join([item for item, cnt in Counter("loveleee").most_common() for _ in range(cnt)])
      'eeeellov'
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-02-06
        • 2013-09-10
        • 2017-03-05
        • 2019-09-17
        • 2020-12-13
        • 2014-01-10
        • 1970-01-01
        • 2014-02-14
        相关资源
        最近更新 更多