Список понимания, чтобы найти подходящих паренов - PullRequest
0 голосов
/ 15 ноября 2018

Я пытаюсь придумать понимание списка, которое будет соответствовать открытым и закрытым паранам. Пока у меня есть эти два утверждения, которые захватывают два списка открытых и закрытых паренов отдельно

my_str = "hanz(and(franz/bob())+ 7) + tom(2)"

Возьмите idx открытых паренов:

[ i for i,c in enumerate(my_str) if c == '(']

# [4, 8, 18, 31]

Возьмите idx близких паренов:

[ i for i,c in enumerate(my_str) if c == ')']

# [19, 20, 24, 33]

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

т.е.

[ ???? for i,c in enumerate(my_str) ???]

# [(4,24), (8,20), (18,19), (31,33)]

Ответы [ 2 ]

0 голосов
/ 15 ноября 2018

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

my_str = "hanz(and(franz/bob())+ 7) + tom(2)"
stack = []
parens = []
for i, c in enumerate(my_str):
    if c == "(":
        stack.append(i)
    elif c == ")":
        parens.append((stack.pop(), i))
print(parens) # [(18, 19), (8, 20), (4, 24), (31, 33)]

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

stack = []
parens = [(stack.pop(), i) for i, c in enumerate(my_str)
          if c == "(" and stack.append(i) or c == ")"]
print(parens) # [(18, 19), (8, 20), (4, 24), (31, 33)]

При этом используется тот факт, что and и or оцениваются на короткое замыкание, поэтому он будет append элементов только если c == "(", но затемсбой, потому что append возвращает None и добавляет элементы к результатам, только если второе условие, c == ")" истинно, выталкивает позицию самого последнего ( из стека.

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

0 голосов
/ 15 ноября 2018

Как упомянуто @Tordek, хотя не невозможно, это не очень практично,

Для полноты, однако, вот решение:

my_str = "hanz(and(franz/bob())+ 7) + tom(2)"

 pt_arr = [ 1 if c == '(' else -1 for i,c in enumerate(my_str ) if c == ')' or c == '(']
idx_arr = [ i for i,c in enumerate(my_str ) if c == ')' or c == '(']

[(idx_arr[strt_idx],idx_arr[strt_idx + [j for j,d in enumerate([ sum(pt_arr[strt_idx:i + 1]) for i,c in enumerate(pt_arr) if i >= strt_idx]) if d == 0][0]]) for strt_idx,f in enumerate(pt_arr) if f == 1]

# [(4,24), (8,20), (18,19), (31,33)]
...