while 循环等效于具有单个执行帧的“尾递归”。有些问题用递归更容易表达,有些问题用循环更容易表达。使用嵌套的 for 循环可以轻松生成对。
def pairs1(seq``):
n = len(seq)
pairlist = []
for i in range(0, n-1):
for j in range(i+1, n):
pairlist.append((seq[i],seq[j]))
return pairlist
inp = (1, 2, 3)
out = [(1,2), (1,3), (2,3)]
assert pairs1(inp) == out
我通常会使用yield 而不是pairlist.append。请注意在代码中包含测试。作为中间步骤,转换为单个 while 循环。
def pairs2(seq):
jmax = len(seq) - 1
pairlist = []
i = 0
j = i+1
while i < jmax:
pairlist.append((seq[i],seq[j]))
if j < jmax:
j += 1
else:
i += 1
j = i+1
return pairlist
assert pairs2(inp) == out
现在转换为使用嵌套尾递归闭包而不是 while 语句并不难。
def pairs3(seq):
jmax = len(seq) - 1
pairlist = []
i = 0
j = i+1
def inner():
nonlocal i, j
if i < jmax:
pairlist.append((seq[i],seq[j]))
if j < jmax:
j += 1
else:
i += 1
j = i+1
inner()
inner()
return pairlist
assert pairs3(inp) == out
这是一种更传统的形式。
def pairs4(seq, i, j, pairlist):
jmax = len(seq) - 1
if i < jmax:
pairlist.append((seq[i],seq[j]))
if j < jmax:
return pairs4(seq, i, j+1, pairlist)
else:
return pairs4(seq, i+1, i+2, pairlist)
else:
return pairlist
assert pairs4(inp, 0, 1, []) == out
严格的功能主义者会用 pairtuple 替换 pairlist,用 () 替换初始的 [],并在递归调用中用元组添加替换 list.append 突变。第一次调用应该是这样的。
return pairs4(seq, i, j+1, pairtuple + ((seq[i],seq[j])))
在 Python 中,加法中的所有复制都会将 O(N) 函数转换为 O(N**2) 函数,所以我不会那样做。