我正在尝试提供一个与打开和关闭括号匹配的列表理解功能。到目前为止,我有这两个语句分别获取打开和关闭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)]
答案 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)]
这利用了and
和or
经过短路评估的事实,因此仅当append
时它会c == "("
个项目,但由于{{1 }}返回append
,并且仅在第二个条件None
为true时才向结果中添加元素,从而从堆栈中弹出最近的c == ")"
的位置。
至少,这并非完全滥用列表理解,因为结果没有被丢弃,而是实际上是期望的结果,并且比you具有的三个列表理解(尽管那些列表理解更容易理解)不会产生副作用),但是一种“方便”的方法更好的解决方案是:使其具有功能,而不管它有多少行。