2017-02-15 5 views
3

Я пытаюсь распечатать пару ключевых значений в том же порядке, что и в выводе 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}) 

Есть ли способ, где я могу напечатать только первый ключ, значение пары?

Я в основном пытаюсь напечатать первый повторяющийся символ в заданной строке.

+1

Что вы подразумеваете под _первым ключом, значением pair_? – Arman

+0

А что такое первый повторный символ в этом случае? – Kasramvd

+0

Я хочу напечатать {'u': 2} – Vishwak

ответ

-1

Из того, что я понимаю, я думаю, что вы ищете что-то вроде этого:

print c.most_common()[0] 

Это дает OUTPUT ('u', 2)

+0

Не уверен, почему это было приостановлено после upvote :( –

+3

Довольно уверен, что это не сработает - на основе описания автора вопроса «попытка распечатать первый повторяющийся символ в заданной строке». Если строка была, например, aaxxxxxxxxxxxxx'', ваш метод вернет 'x', когда искатель пожелает' a'. – asongtoruin

4

Проблема заключается в том, что __repr__ используется первый суперкласса (потому что вы не» t переопределяет его), и это 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)] 
+0

Спасибо @MSeifert. Это именно то, что я искал. Думаю, мой подход OrderedCounter был неправильным для проблемы, которую я пытался решить. – Vishwak

2

Вам не нужно Count или OrderedDict для выполнения этой задачи. Вот оптимизированный подход (для строки длиной n сложности O (п)):

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 

Также вы можете выполнить эту задачу еще быстрее, используя suffix tree, особенно если вы хотите выполнить ее на большом количестве данных. Вот оптимизированная реализация этого алгоритма сама по себе в github.Вы можете также использовать документацию и полезные ссылки, если вы не знакомы с этой структурой данных и алгоритма https://github.com/kasramvd/SuffixTree

В качестве другого линейного на основе ответа, используя str.counter в выражении генератора вы можете использовать следующий подход, предложенный @Stefan Pochmann:

next((c, s.count(c)) for c in s if s.count(c) > 1) 
+0

Оба подхода - это «O (n)», это просто, что 'str.count' намного быстрее, чем' iterating' над строкой вручную или с помощью 'Counter'. – MSeifert

+0

В какое время вы получаете для' next ((c, s.count (c)) для c in s, если s.count (c)> 1) '? –

+0

@MSeifert Да, но это не из-за' counter', потому что вы перебираете строку 2 раза, один раз при создании объекта-счетчика и один раз для поиска ожидаемого персонажа. этот подход не учитывается от начала строки, которую он рассчитывает, от индекса последней находки до конца. Хотя индексирование требует времени, но это так дешевле, чем подсчет. – Kasramvd

-1

Если вам нужен счетчик где-то вниз по линии, можно фильтровать и сортировать его, чтобы получить то, что вы ищете:

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)