As an exercise, I've been trying out various ways of generating all permutations of a list in Python -- recursive, non-recursive... -- and comparing the performance with itertools.permutations()
. But I'm having trouble with the generator version of the recursive method, which doesn't finish cleanly with a StopIteration
exception, but instead throws an IndexError
:
def spawnperms(alist):
"""same algorithm as recursive option, but a generator"""
if (alist == []):
yield []
for perm in spawnperms(alist[:-1]):
for i in range(len(perm)+1):
yield perm[:i] + [alist[-1]] + perm[i:]
Calling this from the Python interpreter:
>>> for i in spawnperms(range(3)):
... print i
...
[2, 1, 0]
[1, 2, 0]
[1, 0, 2]
[2, 0, 1]
[0, 2, 1]
[0, 1, 2]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in spawnperms
File "<stdin>", line 5, in spawnperms
File "<stdin>", line 5, in spawnperms
File "<stdin>", line 7, in spawnperms
IndexError: list index out of range
Ouch. I tried stepping through it with pdb
, which nearly created a stack overflow in my brain, but what I understood is that the recursion "reaches down" to the empty list, and then the outer (I think) for
loop runs out of indices.
How can I correct my code?
EDIT: One learning from Mark Byers' deceptively simple correct answer is that clean coding practices can prevent mistakes. Had I used an else
systematically after if
, regardless of whether I thought the condition could ever be revisited, this wouldn't have happened. And it still feels very stupid!