我正在尝试按照与 OrderedCounter 输出中显示的顺序相同的顺序打印出键值对。
from collections import Counter, OrderedDict
class OrderedCounter(Counter, OrderedDict):
pass
c = OrderedCounter('supernatural')
print c
我得到以下输出:
OrderedCounter({'u': 2, 'r': 2, 'a': 2, 's': 1, 'p': 1, 'e': 1, 'n': 1, 't': 1, 'l': 1})
有没有办法我只能打印出第一个键,值对?
我基本上是在尝试打印给定字符串中的第一个重复字符。
问题是__repr__
被第一个超类使用(因为你不覆盖它(,这是Counter
.Counter
的表示形式是按值降序排序。你子类OrderedDict
并且sorted
是稳定的这一事实使"u"
看起来是第一个元素。
但是,Counter
不提供__iter__
方法,因此您将使用 OrderedDict
的__iter__
,它只是保留广告顺序:
>>> next(iter(c.items()))
('s', 1)
要获得第一个重复字符,只需使用理解:
>>> next((key, value) for key, value in c.items() if value > 1)
('u', 2)
(对于 Python2,您可能希望使用 iteritems()
而不是 items()
(
若要打印第一个最常见的值,可以使用 Counter.most_common
方法:
>>> c.most_common(1)
[('u', 2)]
此任务不需要Count
或OrderedDict
。这是一个优化的方法(对于长度n
复杂度为 O(n( 的字符串(:
In [35]: def first_repeated(s):
seen = set()
for i, j in enumerate(s):
if j in seen: # membership check in set is O(1)
return j, s.count(j, i + 1) + 2
seen.add(j)
....:
In [36]: first_repeated(s)
Out[36]: ('u', 2)
以下是其他答案的基准测试,显示此方法快了近 4-5 倍:
In [39]: def counter_based(s):
....: c = Counter(s)
....: return next(key for key in c if c[key] > 1)
....:
In [40]: %timeit counter_based(s)
100000 loops, best of 3: 5.09 us per loop
In [41]: %timeit first_repeated(s)
1000000 loops, best of 3: 1.71 us per loop
此外,如果您想对大量数据执行后缀树,您可以使用后缀树更快地完成此任务。这是我自己在 github 中对该算法的优化实现。如果您不熟悉此数据结构和算法 https://github.com/kasramvd/SuffixTree,也可以使用文档和有用的链接
作为在生成器表达式中使用str.counter
的另一个基于线性的答案,您可以使用 @Stefan Pochmann 建议的以下方法:
next((c, s.count(c)) for c in s if s.count(c) > 1)
据我了解,我认为您正在寻找这样的东西:
print c.most_common()[0]
这提供了输出('u', 2)
则可以对其进行过滤和排序以获取所需的内容:
from collections import Counter
input_string = 'supernatural'
c = Counter(input_string)
print sorted((pair for pair in c.items() if pair[1]>1), key=lambda x: input_string.index(x[0]))[0]
我们过滤计数器以仅返回多次出现的字母,根据其在输入字符串中的位置对其进行排序,并返回我们找到的第一对。因此,这打印('u', 2)