Finding All Permutations of a String in Python

In my quest to learn the intricacies of Python, I came across one of my favorite algorithms; finding all the possible permutations of a string.

To lay it out:

# Given string 'ab'
# Permutation list ['a', 'ab', 'b', 'ba']

This is a poster child for recursion. To set it up, we'll have our primary function, string_permutations, but also define a subroutine that will do our recursive dirt work. We'll also create a combos list to hold onto our permutations.

#!/usr/bin/env python -tt

def string_permutations(string):

  def sub_routine(...some args):
    combos = []
    return combos

  return sub_routine(...some args)

def main():  
  # print string_permutations('ab')

if __name__ == "__main__":  
  main()

We'll pass in two list arguments to sub_routine. The first will hold on to all the characters that we have 'used' so far, and the other will hold on to the characters that we still have left to use. We can call sub_routine in our parent function beginning with an empty list for 'used' characters, and a list made of all characters in the target string as the initial 'left' characters.

...
def sub_routine(used, left):  
  combos = []
  return combos

return sub_routine([], list(string))  

Inside our sub_routine function, we can begin generating our permutations. First, we'll loop through each index in the left list. Looping the index and not the character itself, will make it easier to manage the recursion later on. Then, we'll remove the character from the left list at that index and add it to the end of the used list.

The used list will represent our permutation so far. We're not implementing restrictions on the size of the permutations, so each iteration will represent a unique permutation. We can then push that permutation to our combos list.

...
def sub_routine(used, left):  
  combos = []

  for i in range(0, len(left)):
    ch = left.pop(i)
    used.append(ch)

    combos.append(''.join(used))


  return combos

return sub_routine([], list(string))  

And now, here comes the fun part. For each permutation we start building, we need to add on all combinations of remaining characters. So let's get a little recursive.

What we'll do is pass in the new used and left lists to a recursive call to our sub_routine. Since our sub_routine will return all of its subsequent permutations, we can concatenate the result of our recursive call with our combos array.

The tricky part comes in after we make the recursive call. We have to reset the contents of left and used so that when we continue on in the for loop, we can access the next character properly.

For example, on the first iteration of 'ab':

# First iteration: 
# ch will equal 'a'
# We will put 'a' into our used array as the first character.
# All subsequent recursive calls down this path will have 'a' as the first character.
# We finish the recursive chain, and replace 'a' in left and remove 'a' from used.


#Second Iteration:
# ch will equal 'b'
# We will put 'b' into our used array as the first character.
# All subsequent recursive calls down this path will have 'b' as the first character.

All of these steps will be repeated as part of the recursion with the result that each permutation will be visited.

#!/usr/bin/env python -tt

def string_permutations(string):

  def sub_routine(used, left):

    combos = []

    for i in range(0, len(left)):
      ch = left.pop(i)
      used.append(ch)

      combos.append(''.join(used))

      # Append the results of the 
      # recursive call to our combos list
      combos = combos + sub_routine(used, left)


      # Remove ch from used
      used.pop(-1)
      # Splice ch back into left at its original index
      left[i:0] = [ch]

    return combos

  return sub_routine([], list(string))

def main():  
  print string_permutations('ab')

if __name__ == "__main__":  
  main()

Knocking out a permutations algorithm always makes me feel like a recursive badass.