Спрятать «следующий» и «предыдущий» ссылки в связанном списке

У меня есть список строк, которые представляют проходы структуры данных. Я хочу свернуть переходы списка ссылок в более компактное представление. Для этого я хотел бы подсчитать количество смежных next и prev ссылок и свернуть их в одно целое.

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

 ['modules'] --> ['modules'] ['modules', 'next'] --> ['modules', 1] ['modules', 'prev'] --> ['modules', -1] ['modules', 'next', 'next', 'next', 'txt'] --> ['modules', 3, 'txt'] ['modules', 'next', 'prev', 'next', 'txt'] --> ['modules', 1, 'txt'] ['super_blocks', 'next', 's_inodes', 'next'] --> ['super_blocks', 1, 's_inodes', 1] 

Каждая next ссылка рассчитывается как +1, а каждый prev равен -1. Смежные next s и prev s отменяют друг друга. Они могут прийти в любом порядке.

У меня есть рабочее решение для этого, но я изо всех сил стараюсь найти удовлетворительно элегантное и Pythonic решение.

Как насчет:

 def convert(ls): last = None for x in ls: if x == 'prev': x = -1 if x == 'next': x = +1 if isinstance(x, int) and isinstance(last, int): x += last elif last: # last is not None if you want zeroes yield last last = x yield last 

Вы можете использовать генератор:

 def links(seq): it = iter(seq) while True: el = next(it) cnt = 0 try: while el in ['prev', 'next']: cnt += (1 if el == 'next' else -1) el = next(it) finally: if cnt != 0: yield cnt yield el print list(links(['modules', 'next', 'prev', 'next', 'txt'])) 

Стоит отметить, что последовательность, содержащая равное число next и prev полностью удаляется. Было бы легко изменить код, чтобы создать 0 если это то, что вы хотите (я думаю, что требования немного неясны в этом).

Вот самый простой подход, который пришел на ум. Простой является ценным качеством для понимания, отладки и будущего обслуживания.

 def process(l): result = [] count = 0 keepCount = False for s in l: if s == "next": count += 1 keepCount = True elif s == "prev": count -= 1 keepCount = True else: if keepCount: result.append(count) count = 0 keepCount = False result.append(s) # end if # end for if keepCount: result.append(count) return result # end process() 

Тем не менее, мне нравится использование NPE генератора. (мой можно легко преобразовать, изменив «result.append ()» на «yield»). Его (оригинальный) ответ почти такой же, как у меня, но я включаю счет 0 в том случае, если соседние / предыдущие токены смежны в равных количествах.

Как насчет небольшого reduce() ?

 def collapse(lst): was_link = [False] # No nonlocal in Python 2.x :( def step(lst, item): val = { 'prev': -1, 'next': 1 }.get(item) if was_link[0] and val: lst[-1] += val else: lst.append(val or item) was_link[0] = bool(val) return lst return reduce(step, [[]] + lst)