Python按频率排序字符串 - 无法使用sorted()函数排序

时间:2017-06-07 13:36:00

标签: python string sorting frequency

我有一个问题,按频率排序一个简单的字符串(我得到一个字符串作为输入,我需要将一个排序的字符串作为输出按降序返回)。 让我举个例子(原始单词包含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'不知怎的?或者我错过了什么?

3 个答案:

答案 0 :(得分:4)

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

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'

答案 1 :(得分:0)

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

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

答案 2 :(得分:0)

问题是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"然后才会出现只有具有不同计数的字符:'v'

如果你不关心具有相同数量的元素的顺序(只是按字符分组),你甚至不需要sorted,只需将{{3}的结果展平}}:

>>> ''.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'