2016-01-23 4 views
0

Я ищу элегантный «Pythonic» способ циклического ввода в группы определенного размера. Но размер групп меняется, и вы не знаете размер определенной группы, пока не начнете синтаксический разбор.Python нерегулярная петля

На самом деле я забочусь только о группах двух размеров. У меня есть большая последовательность входных данных, которые входят в группы большей части размера X, но иногда имеют размер Y. В этом примере можно сказать, что X = 3 и Y = 4 (моя фактическая проблема - X = 7 и Y = 8). Я не знаю до середины группы элементов, если это будет группа размера X или элементов размера Y.

В моей проблеме я имею дело с строками ввода, но для упрощения я проиллюстрирую символы.

Так что, если это группа определенного размера, я знаю, что всегда буду вводить вход в той же последовательности. Например, если это группа размера X, я получаю элементы типа [a, a, b], но если это группа размера Y, я получаю элементы типа [a, a, c, b]. f это что-то типа «a». Я хочу обработать его определенным образом и «b» другой и т. д.

Очевидно, мне нужно в какой-то момент проверить элемент, чтобы определить, относится ли это группа типа 1 или Другие. Как показано выше, я не могу просто проверить тип каждого элемента, потому что в последовательности могут быть два одинаковых. Кроме того, группы могут быть одной и той же моделью в начале и только отличаться ближе к концу. В этом примере самое раннее, что я могу проверить, есть ли у меня размер X или размер группы Y, проверяя третий элемент (чтобы увидеть, имеет ли он тип «c» или тип «b»).

У меня есть решение с циклом for с открытым индексом и двумя дополнительными переменными, но мне интересно, есть ли более элегантное решение.

Вот мой код.Я поставил pass заявление на месте, где я хотел бы сделать фактический разбор в зависимости от того, какого типа он:

counter = 0 
group = 3 
for index, x in enumerate("aabaabaacbaabaacbaabaab"): 
    column = index - counter; 
    print(str(index) + ", " + x + ", " + str(column)) 

    if column == 0: 
     pass 
    elif column == 1: 
     pass 
    elif column == 2: 
     if x == 'c': 
      pass 
     elif x == 'd': 
      group = 4 
    elif column == 3: 
     pass 

    if column + 1 == group: 
     counter += group 
     group = 3 

В примере коды входной поток aabaabaacbaabaacbaabaab так что группы:

  1. AAB (3)
  2. AAB (3)
  3. aacb (4)
  4. AAB (3)
  5. aacb (4)
  6. AAB (3)
  7. AAB (3)
+0

Не могли бы вы а) дать более короткое, точное описание проблемы и b) предоставить [MCVE] (http://stackoverflow.com/help/mcve)? Я пытался три раза прочесть ваш вопрос и не мог расшифровать вопрос. – timgeb

+0

В основном я потребляю последовательность ввода, которую я знаю, это два типа групп. По мере того, как я просматриваю входные данные, я буду в состоянии работать, если я буду в одной группе или другой. Несмотря на то, что у меня есть что-то, что работает в моем текущем решении, я чувствую, что дополнительные переменные - это что-то, что будет в стиле C/Java для цикла с аргументами case, но оно неудобно в Python. – freshnewpage

ответ

4

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

def getGroups (iterable): 
    group = [] 
    for item in iterable: 
     group.append(item) 
     if len(group) == 3 and group[2] == 'c': 
      yield group 
      group = [] 
     elif len(group) == 4 and group[2] == 'd': 
      yield group 
      group = [] 

for group in getGroups('abcabcabdcabcabdcabcabc'): 
    print(group) 
['a', 'b', 'c'] 
['a', 'b', 'c'] 
['a', 'b', 'd', 'c'] 
['a', 'b', 'c'] 
['a', 'b', 'd', 'c'] 
['a', 'b', 'c'] 
['a', 'b', 'c'] 
0

С вашим конкретным примером, вы можете использовать регулярные выражения:

>>> s="aabaabaacbaabaacbaabaab" 
>>> re.findall(r'aac?b', s) 
['aab', 'aab', 'aacb', 'aab', 'aacb', 'aab', 'aab'] 

Если вы хотите парсер, который делает то же самое, что вы можете сделать:

def parser(string, patterns): 
    patterns=sorted(patterns, key=len, reverse=True) 
    i=0 
    error=False 
    while i<len(string) and not error: 
     for pat in patterns: 
      j=len(pat) 
      if string[i:i+j]==pat: 
       i+=j 
       yield pat 
       break 
     else: 
      error=True 

    if error or i<len(string): 
     raise SyntaxWarning, "Did not match the entire string" 

>>> list(parser(s, ['aab', 'aacb'])) 
['aab', 'aab', 'aacb', 'aab', 'aacb', 'aab', 'aab'] 
+0

Несомненно, это работает для примера, но, как я уже упоминал, эта строка является только иллюстративной; каждый символ представляет собой строку ввода. Реальный вход представляет собой большую последовательность строк. – freshnewpage

+0

Но вы заявляете, что имеете дело с этим вводом строки за строкой. Это очень типичное приложение regex. Даже если ваши данные 7, но иногда 8 и просто изменяются в некотором дополнительном элементе Nth - регулярное выражение является надежным способом распознавания. – dawg

+0

Возможно, мой пример путал вещи. В моем примере строка предназначена для представления списка строк. Символ в строке представляет целую строку. Я делал это так, чтобы быть кратким. Насколько мне известно, вы не можете повторно задавать группы строк за раз. Более точный пример: [альфа, альфа, бета, альфа, альфа, гамма, бета, альфа, альфа, бета. – freshnewpage

2

Похоже, вам нужен простой автоматам с откатами, например:

def parse(tokens, patterns): 

    backtrack = False 
    i = 0 

    while tokens: 

     head, tail = tokens[:i+1], tokens[i+1:] 
     candidates = [p for p in patterns if p.startswith(head)] 
     match = any(p == head for p in candidates) 

     if match and (backtrack or len(candidates) == 1 or not tail): 
      yield head 
      tokens = tail 
      backtrack = False 
      i = 0 

     elif not candidates: 
      if not i or backtrack: 
       raise SyntaxError, head 
      else: 
       backtrack = True 
       i -= 1 

     elif tail: 
      i += 1 

     else: 
      raise SyntaxError, head 

tokens = 'aabaabcaabaabcxaabxxyzaabx' 
patterns = ['aab', 'aabc', 'aabcx', 'x', 'xyz'] 

for p in parse(tokens, patterns): 
    print p 
Смежные вопросы