Okay, let's begin.
Starting code
(minus print statements)
def perm(l):
sz = len(l)
if sz <= 1:
return [l]
return [p[:i]+[l[0]]+p[i:] for i in range(sz) for p in perm(l[1:])]
Revision 1
def perm(s):
# Base case: an empty list or a list with only one item has only one
# permutation
if len(s) <= 1:
return [s]
return [p[:i] + [s[0]] + p[i:]
for i in range(len(s)) for p in perm(s[1:])]
- Rename
l
to s
- Remove
sz
, instead using len(s)
directly. We might lose a tiny bit of efficiency, but we gain a huge amount of readability
- Fix spacing in list comprehension
Revision 2
def perm(s):
# Base case: an empty list or a list with only one item has only one
# permutation
if len(s) <= 1:
return [s]
# A list of permutations
permutations = []
for i in range(len(s)):
# Recursively find all permutations of s[1:]
for p in perm(s[1:]):
# Insert s[0] in position i
permutations.append(p[:i] + [s[0]] + p[i:])
return permutations
- Break apart the list comprehension
Revision 3
def perm(s):
# Base case: an empty list or a list with only one item has only one
# permutation
if len(s) <= 1:
return [s]
# A list of permutations
permutations = []
# Recursively find all permutations of s[1:]
for p in perm(s[1:]):
for i in range(len(s)):
# Insert s[0] in position i
permutations.append(p[:i] + [s[0]] + p[i:])
return permutations
- Change the nesting of the
for
loops. Now, you can say: for each permutation, take each position i
, and add a copy of that permutation with s[0]
inserted in each position i
. This gets clearer in the next few revisions.
Revision 4
def perm(s):
# Base case: an empty list or a list with only one item has only one
# permutation
if len(s) <= 1:
return [s]
# Recursively find all permutations of s[1:]
shortperms = perm(s[1:])
# A list of permutations
permutations = []
for shortperm in shortperms:
for i in range(len(s)):
# Make a copy of shortperm
spcopy = shortperm[:]
# Insert s[0] in position i
spcopy.insert(s[0], i)
# Add this to the list of permutations
permutations.append(spcopy)
return permutations
- Moved the
perm
function call. Now, the shortperms
variable will contain all the permutations of s[1:]
, which is s
minus the first item.
- Changed the list addition into three operations:
- Make a copy of
shortperm
- Insert the first item in s
- Add that list to
permutations
Revision 5
def perm(s):
# Base case: an empty list or a list with only one item has only one
# permutation
if len(s) <= 1:
return [s]
# Recursively find all permutations of s[1:]
shortperms = perm(s[1:])
# A list of permutations
permutations = []
for shortperm in shortperms:
for i in range(len(shortperm) + 1):
# Make a copy of shortperm
spcopy = shortperm[:]
# Insert s[0] in position i
spcopy.insert(s[0], i)
# Add this to the list of permutations
permutations.append(spcopy)
return permutations
len(s)
is the same as len(shortperm) + 1
, because each shortperm
is a permutation of the items in s
, minus the first one. However, this is probably more readable.
Final code
With a docstring comment
def perm(s):
"""Return a list of all permutations of the items in the input
sequence."""
# Base case: an empty list or a list with only one item has only one
# permutation
if len(s) <= 1:
return [s]
# Recursively find all permutations of s[1:]
shortperms = perm(s[1:])
# A list of permutations
permutations = []
for shortperm in shortperms:
for i in range(len(shortperm) + 1):
# Make a copy of shortperm
spcopy = shortperm[:]
# Insert s[0] in position i
spcopy.insert(s[0], i)
# Add this to the list of permutations
permutations.append(spcopy)
return permutations