Permutation algorithm in Python
In this article, I will introduce permutation algorithms.
Straightforward way
- 1st step: Choose one element from given list.
- 2nd step: Choose another element from list that doesn't have the element chosen in 1st step.
- 3rd step: Choose another element from list that doesn't have the element chosen in 1st and 2nd step.
- nth step: Loop these steps unless list is empty.
Above steps can be coded by calling function recursively.
def perm(lst, permutation=[]):
if not lst:
# if list is empty, finish choosing steps
print(permutation)
else:
# 'for ... in' loop represents each steps
for chosen in lst:
# 'rest_list' is a list that doesn't have the element 'chosen'
rest_list = [item for item in lst if item != chosen]
# add a element that is chosen in this step
# ('permutation' has chosen elements before this step)
chosen_elements = permutation + [chosen]
# go to next step
perm(rest_list, chosen_elements)
perm([1, 2, 3])
Output:
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]
More recursive way
As below, looking more carefully, you can find recursive pattern.
perm([]) => []
perm([1]) => [1]
# adding '1' to the result of 'perm([])': [ ]
^
perm([1, 2]) => [1, 2], [2, 1]
# adding '2' to the result of 'perm([1])': [ 1 ]
^ ^
perm([1, 2, 3]) => [1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]
# adding '3' to the result of 'perm([1, 2])': [ 1 , 2 ], [ 2 , 1 ]
^ ^ ^ ^ ^ ^ ^ ^
I think to separate helper functions (interleave and flatten) let you to understand this algorithm more easily.
Helper functions:
import copy
def interleave(lst, element):
result = []
for i in range(len(lst) + 1):
l = copy.copy(lst)
l.insert(i, element)
result.append(l)
return result
def flatten(lst):
return sum(lst, [])
Recursive algorithm:
def perm_rec(lst):
if not lst:
return [[]]
else:
# when 'lst' is '[1, 2, 3]',
# 'rest_perm' is the result of 'perm_rec([2, 3])'
rest_perm = perm_rec(lst[1:])
# interleave '1' into each result of 'perm_rec([2, 3])
result = flatten([interleave(x, lst[0]) for x in rest_perm])
return result
print(perm_rec([1, 2, 3]))
Output:
[[1, 2, 3], [2, 1, 3], [2, 3, 1], [1, 3, 2], [3, 1, 2], [3, 2, 1]]