Напечатайте первое значение ключа в упорядоченном счетчике
Я пытаюсь распечатать пару "Значение ключа" в том же порядке, что и в выходных данных 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})
Есть ли способ, где я могу распечатать только первый ключ, пара значений?
Я в основном пытаюсь напечатать первый повторяющийся символ в данной строке.
4 ответа
Проблема в том, что __repr__
используется первым суперклассом (потому что вы не переопределяете его), и это Counter
, Представление Counter
является то, что это отсортировано по значениям в порядке убывания. Тот факт, что вы подкласс OrderedDict
а также sorted
стабильным, создается впечатление, что "u"
это первый элемент.
тем не мение Counter
не обеспечивает __iter__
метод, так что вы будете использовать __iter__
из OrderedDict
который просто сохраняет порядок вставки:
>>> 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)