Counter.most_common(n)如何覆盖任意顺序

Mic*_*l B 5 python counter python-2.7

我可以完成秩/排序使用Counter.most_common()的功能,从而避免了这一行:d = sorted(d.items(), key=lambda x: (-x[1],x[0]), reverse=False)??

挑战: 给您一个字符串。该字符串仅包含小写英文字母字符。您的任务是查找字符串中最常见的前三个字符。

输出格式: 将三个最常见的字符及其出现次数打印在单独的行上。按出现次数降序对输出进行排序。如果出现次数相同,请按升序对字符进行排序。

在完成此操作时,我使用了dict,Counter和sort以确保“出现次数相同,以升序对字符进行排序”。内置的Python sorted功能可确保先按计数再按字母顺序排序。我很好奇是否有一种方法可以覆盖Counter.most_common()默认的任意排序/顺序逻辑,因为在选择前3个时似乎无视结果的字典顺序。

import sys
from collections import Counter

string = sys.stdin.readline().strip()
d = dict(Counter(string).most_common(3))
d = sorted(d.items(), key=lambda x: (-x[1],x[0]), reverse=False)

for letter, count in d[:3]:
    print letter, count
Run Code Online (Sandbox Code Playgroud)

smc*_*mci 6

是的,文档明确指出Counter.most_common()计数相等时的(抢七)顺序是任意的

  • 更新:PM2Ring告诉我Counter继承了dict的排序。插入顺序仅在3.6+版本中发生,并且只能在3.7中得到保证。该文档可能会滞后。
  • 在cPython 3.6+中,它们依赖于原始插入顺序(请参阅底部),但不要依赖于该实现,因为根据规范,它不是定义的行为。如您所说,最好完全按照自己的意愿行事。
  • 我在底部展示了如何像您展示的那样使用自己的排序功能进行猴子补丁 Counter.most_common,但这是个皱眉。(您编写的代码可能不小心依赖了它,因此在未打补丁时会中断。)
  • 您可以将其子类化CounterMyCounter从而可以覆盖它most_common。痛苦而不是真正的便携性。
  • 确实,最好的方法就是编写不依赖于以下任意决胜局顺序的代码和测试: most_common()
  • 我同意不most_common()应该硬接线,我们应该能够将比较键或排序函数传递给__init__()

猴子修补Counter.most_common()

def patched_most_common(self):
    return sorted(self.items(), key=lambda x: (-x[1],x[0]))

collections.Counter.most_common = patched_most_common

collections.Counter('ccbaab')
Counter({'a': 2, 'b': 2, 'c': 2})
Run Code Online (Sandbox Code Playgroud)

证明在cPython 3.7中,任意顺序是插入顺序(每个字符的第一次插入):

Counter('abccba').most_common()
[('a', 2), ('b', 2), ('c', 2)]

Counter('ccbaab').most_common()
[('c', 2), ('b', 2), ('a', 2)]
Run Code Online (Sandbox Code Playgroud)