2016-04-10 2 views
1

У меня есть небольшой вопрос о том, как проверить и сравнить два или более символов в списке на Python.Список Python, сравнивающий символы и подсчет их

Например, у меня есть строка «cdcdccddd». Я сделал список из этой строки, чтобы легче сравнивать символы. И нужный вывод: c: 1 d: 1 c: 1 d: 1 c: 2 d: 3 Итак, он подсчитывает символы, если вначале это не то же самое, что и второе, счетчик = 1, если второй - тот же, что и третий, тогда счетчик равен +1 и нужно проверить третье с четвертым и так далее.

I got so far this algorithm: 
text = "cdcdccddd" 
l = [] 
l = list(text) 
print list(text) 

for n in range(0,len(l)): 
    le = len(l[n]) 
    if l[n] == l[n+1]: 
     le += 1 
     if l[n+1] == l[n+2]: 
      le += 1 
     print l[n], ':' , le 
    else: 
     print l[n], ':', le 

но его не работает хорошо, потому что он считает первый и второй элемент, но не второй и третий. Для этого выхода будут:

c : 1 
d : 1 
c : 1 
d : 1 
c : 2 
c : 1 
d : 3 

Как сделать этот алгоритм лучше?

Спасибо!

+0

Как вы сказали, что этот алгоритм не правильно в базе, потому что вы не можете рассчитывать все вхождения, как это (так как вы не знаете числа повторяющихся последовательностей). Одним из способов преодоления этой проблемы является категоризация ваших символов, а затем подсчет количества символов в каждом подмножестве. – Kasramvd

ответ

3

Вы можете использовать itertools.groupby:

from itertools import groupby 
s = "cdcdccddd" 

print([(k, sum(1 for _ in v)) for k,v in groupby(s)]) 
[('c', 1), ('d', 1), ('c', 1), ('d', 1), ('c', 2), ('d', 3)] 

Последовательные символы будут сгруппированы вместе, так что каждый k является полукокс из этой группы, вызывая sum(1 for _ in v) дает нам длину каждой группы таким образом, мы в конечном итоге с (char, len(group)) парами.

Если мы запустим его в IPython и вызова списка по каждому v должно быть на самом деле ясно, что происходит:

In [3]: from itertools import groupby 

In [4]: s = "cdcdccddd" 

In [5]: [(k, list(v)) for k,v in groupby(s)] 
Out[5]: 
[('c', ['c']), 
('d', ['d']), 
('c', ['c']), 
('d', ['d']), 
('c', ['c', 'c']), 
('d', ['d', 'd', 'd'])] 

Мы также можем свернуть наш собственный довольно легко:

def my_groupby(s): 
    # create an iterator 
    it = iter(s) 
    # set consec_count, to one and pull first char from s 
    consec_count, prev = 1, next(it) 
    # iterate over the rest of the string 
    for ele in it: 
     # if last and current char are different 
     # yield previous char, consec_count and reset 
     if prev != ele: 
      yield prev, 
      consec_count, = 0 
     prev = ele 
     consec_count, += 1 
    yield ele, consec_count 

Что дает us the same:

In [8]: list(my_groupby(s)) 
Out[8]: [('c', 1), ('d', 1), ('c', 1), ('d', 1), ('c', 2), ('d', 3)] 
1

Это похоже на регулярное выражение повторяющихся символов, поэтому вы можете зе регулярное выражение с повторяющимися символами, а затем найти длину каждого матча:

import re 
text = "cdcdccddd" 
matches = re.findall(r'(.)(\1*)', text) 
result = ['{}: {}'.format(match[0], len(''.join(match))) for match in matches] 

Результат:

>>> print(*result, sep='\n') 
c: 1 
d: 1 
c: 1 
d: 1 
c: 2 
d: 3 
1

Первая вещь, строки уже перечислены в Python, так что вы можете просто сказать for character in text:, чтобы каждый символов.

Я хотел бы попробовать что-то вроде этого:

currentchar = text[0] 
currentcount = 0 

for c in text[1:]: 
    if c == currentchar: 
     currentcount += 1 
    else: 
     print(currentchar + ": " + str(currentcount+1)) 
     currentchar = c 
     currentcount = 0 

print(currentchar + ": " + str(currentcount+1)) 
+0

Строки - это последовательности, но не списки. Список - это отдельная вещь, отличная от строк. – zondo

+0

Да, вы правы, я должен был сказать, что они могут использоваться * как списки. – tryexceptpass

Смежные вопросы