下面是一個使用一個額外的參數記住列表的起始位置代碼的一個版本做到這一點。我把你的函數改成了一個遞歸生成器,所以它產生了這些值,而不是將它們打印出來。我還將high
更改爲stop
,這符合Python的分片中使用的約定,例如seq[start:stop]
和range(start, stop)
。
def permute(lst, start, stop, low=None):
if low == stop - 1:
yield lst[start:stop]
if low is None:
low = start
for index in range(low, stop):
lst[index], lst[low] = lst[low], lst[index]
for t in permute(lst, start, stop, low + 1):
yield t
lst[index], lst[low] = lst[low], lst[index]
# Test
lst = list(range(5))
print(list(permute(lst, 1, 4)))
for t in permute(lst, 0, 3):
print(t)
輸出
[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 2, 1], [3, 1, 2]]
[0, 1, 2]
[0, 2, 1]
[1, 0, 2]
[1, 2, 0]
[2, 1, 0]
[2, 0, 1]
該代碼工作相同關於Python 2 & 3中,儘管在Python 3它可以通過使用製成稍微更有效的(和更緊湊) yield from
語法。替換for t in permute
...循環與
yield from permute(lst, start, stop, low + 1)
在Python 3,您還可以在一個更緊湊的方式創建值列表:
[*permute(lst, 1, 4)]
最後,這裏又建了遞歸發生器從你的算法,但它排列整個列表。當然,你可以使用接口函數調用它來排列子列表。
def permuter(lst):
if not lst:
yield lst
for index in range(len(lst)):
lst[index], lst[0] = lst[0], lst[index]
first = lst[:1]
for t in permuter(lst[1:]):
yield first + t
lst[index], lst[0] = lst[0], lst[index]
def permute(lst, start, stop):
yield from permuter(lst[start:stop])
lst = list(range(5))
print(list(permute(lst, 1, 4)))
您正在更改'lst',您可能需要創建一個新列表來保存排列和'返回'它。爲什麼使用遞歸? – AChampion
我不認爲它可以很容易地完成,沒有破壞算法的優雅。你可能可以通過給予'permute'來實現一個額外的arg來保持原來的'low' arg,但這有點笨重。簡單的解決方案是讓另一個函數充當遞歸「permute」函數的接口。所以你調用接口函數,並用列表的一部分調用'permute'。 –
如果你不需要遞歸,你可以使用'itertools.permutation(lst [low:high + 1])'。 – Eric