使用迴圈循序處理List中元素的問題,基本上都可轉為遞迴解,不必使用計數器,只要有辦法取List的head與tail就可以了。如果迴圈中又有迴 圈,基本上就是處理兩個問題了,函數式就是強迫你要分解問題。舉例來說:
def toPFix(infix, isPost):
expr = infix if isPost else infix[::-1]
stack = []
output = []
toStack, toOutput = ('(', ')') if isPost else (')', '(')
for c in expr:
if c == toStack:
stack.append(c)
elif c in ['+', '-', '*', '/']:
while stack and priority(stack[-1]) >= priority(c):
output.append(stack.pop())
stack.append(c)
elif c == toOutput:
while stack[-1] != toStack:
output.append(stack.pop())
stack.pop()
else:
output.append(c)
while stack:
output.append(stack.pop())
return ''.join(output if isPost else output[::-1])
好幾個迴圈是吧!基本上從最內層開始,除了無窮迴圈之外,迴圈都會有終止條件,要將之轉為遞迴終止條件,所以函數式一定會要思考邊界在哪,先處理for中 第一個while迴圈:
def toPFix(infix, isPost):
expr = infix if isPost else infix[::-1]
stack = []
output = []
toStack, toOutput = ('(', ')') if isPost else (')', '(')
def procOpt(c, stack, output):
if stack == [] or priority(stack[-1]) < priority(c):
return (stack + [c], output)
else:
return procOpt(c, stack[0:-1], output + stack[-1:])
for c in expr:
if c == toStack:
stack.append(c)
elif c in ['+', '-', '*', '/']:
# while stack and priority(stack[-1]) >= priority(c):
# output.append(stack.pop())
# stack.append(c)
stack, output = procOpt(c, stack, output)
elif c == toOutput:
while stack[-1] != toStack:
output.append(stack.pop())
stack.pop()
else:
output.append(c)
while stack:
output.append(stack.pop())
return ''.join(output if isPost else output[::-1])
procOpt就是一個子問題的解法,所以先讓它傳回值指定給for中的stack與output,從命令式到函數式要多練習,不要急著一次把所有命令式 改為函數式,要一個一個來,不然會一團亂,精神就是分解問題,解決問題。接著類似的,處理for中第二個while迴圈:
def toPFix(infix, isPost):
expr = infix if isPost else infix[::-1]
stack = []
output = []
toStack, toOutput = ('(', ')') if isPost else (')', '(')
def procOpt(c, stack, output):
if stack == [] or priority(stack[-1]) < priority(c):
return (stack + [c], output)
else:
return procOpt(c, stack[0:-1], output + stack[-1:])
def procPhs(stack, output):
if stack[-1] == toStack:
return (stack[0:-1], output)
else:
return procPhs(stack[0:-1], output + stack[-1:])
for c in expr:
if c == toStack:
stack.append(c)
elif c in ['+', '-', '*', '/']:
stack, output = procOpt(c, stack, output)
elif c == toOutput:
# while stack[-1] != toStack:
# output.append(stack.pop())
# stack.pop()
stack, output = procPhs(stack, output)
else:
output.append(c)
while stack:
output.append(stack.pop())
return ''.join(output if isPost else output[::-1])
現在for中沒有迴圈了,記得迴圈就是要當作子問題來處理。最後來料理for迴圈:
def toPFix(infix, isPost):
toStack, toOutput = ('(', ')') if isPost else (')', '(')
def procOpt(c, stack, output):
if stack == [] or priority(stack[-1]) < priority(c):
return (stack + [c], output)
else:
return procOpt(c, stack[0:-1], output + stack[-1:])
def procPhs(stack, output):
if stack[-1] == toStack:
return (stack[0:-1], output)
else:
return procPhs(stack[0:-1], output + stack[-1:])
def procExpr(expr, stack = [], output = []):
if expr == "":
return output + stack[::-1]
elif expr[0] == toStack:
return procExpr(expr[1:], stack + [expr[0]], output)
elif expr[0] in ['+', '-', '*', '/']:
return procExpr(expr[1:], *procOpt(expr[0], stack, output))
elif expr[0] == toOutput:
return procExpr(expr[1:], *procPhs(stack, output))
else:
return procExpr(expr[1:], stack, output + [expr[0]])
output = procExpr(infix if isPost else infix[::-1])
return ''.join(output if isPost else output[::-1])
注意一下!本來函式中最後一個while迴圈到哪去了?就是procExpr中第一個if中的stack[::-1],因為最後一個while就是將 stack中元素逐一取出,並附加至output後,這不就表示直接將stack反轉再與output串在一起,如果自己寫遞迴函式來反轉程式也是可以, 不過Python中只要用stack[::-1],意思相同。