列出理解以找到匹配的括号

时间:2018-11-15 02:37:19

标签: python list-comprehension

我正在尝试提供一个与打开和关闭括号匹配的列表理解功能。到目前为止,我有这两个语句分别获取打开和关闭parens的两个列表

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

打开括号的IDx:

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

# [4, 8, 18, 31]

获取亲密ID的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 :(得分:0)

就像@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)]

答案 1 :(得分:0)

如评论中所述,正确而简单的方法是使用堆栈:

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)]

这利用了andor经过短路评估的事实,因此仅当append时它会c == "("个项目,但由于{{1 }}返回append,并且仅在第二个条件None为true时才向结果中添加元素,从而从堆栈中弹出最近的c == ")"的位置。

至少,这并非完全滥用列表理解,因为结果没有被丢弃,而是实际上是期望的结果,并且比you具有的三个列表理解(尽管那些列表理解更容易理解)不会产生副作用),但是一种“方便”的方法更好的解决方案是:使其具有功能,而不管它有多少行。