How do you generate all the permutations of a list in Python, regardless of the type of elements in the list?
For example:
permutations([]) [] permutations([1]) [1] permutations([1, 2]) [1, 2] [2, 1] permutations([1, 2, 3]) [1, 2, 3] [1, 3, 2] [2, 1, 3] [2, 3, 1] [3, 1, 2] [3, 2, 1]
#1 building
This solution implements a generator to avoid leaving all permutations in memory:
def permutations (orig_list): if not isinstance(orig_list, list): orig_list = list(orig_list) yield orig_list if len(orig_list) == 1: return for n in sorted(orig_list): new_list = orig_list[:] pos = new_list.index(n) del(new_list[pos]) new_list.insert(0, n) for resto in permutations(new_list[1:]): if new_list[:1] + resto <> orig_list: yield new_list[:1] + resto
#2 building
Starting with Python 2.6 (if you are using Python 3), you can use a standard library tool: itertools.permutations .
import itertools list(itertools.permutations([1, 2, 3]))
If you're using an older version of Python for some reason (< 2.6), or just want to know how it works, this is a good way to do it, excerpted from http://code.activestate.com/recipes/252178/ :
def all_perms(elements): if len(elements) <=1: yield elements else: for perm in all_perms(elements[1:]): for i in range(len(elements)): # nb elements[0:1] works in both string and list contexts yield perm[:i] + elements[0:1] + perm[i:]
Several other methods are listed in the documentation for itertools.permutations. This is a:
def permutations(iterable, r=None): # permutations('ABCD', 2) --> AB AC AD BA BC BD CA CB CD DA DB DC # permutations(range(3)) --> 012 021 102 120 201 210 pool = tuple(iterable) n = len(pool) r = n if r is None else r if r > n: return indices = range(n) cycles = range(n, n-r, -1) yield tuple(pool[i] for i in indices[:r]) while n: for i in reversed(range(r)): cycles[i] -= 1 if cycles[i] == 0: indices[i:] = indices[i+1:] + indices[i:i+1] cycles[i] = n - i else: j = cycles[i] indices[i], indices[-j] = indices[-j], indices[i] yield tuple(pool[i] for i in indices[:r]) break else: return
Another is based on itertools.product:
def permutations(iterable, r=None): pool = tuple(iterable) n = len(pool) r = n if r is None else r for indices in product(range(n), repeat=r): if len(set(indices)) == r: yield tuple(pool[i] for i in indices)
#3 building
stay Python 2.6 and In a later version:
import itertools itertools.permutations([1,2,3])
(returned as a generator. Use list(permutations(l)) to return as a list.)
#4 building
As tzwenn replied, it is possible to iterate over the first element of each permutation. I prefer this solution:
def all_perms(elements): if len(elements) <= 1: yield elements # Only permutation possible = no permutation else: # Iteration over the first element in the result permutation: for (index, first_elmt) in enumerate(elements): other_elmts = elements[:index]+elements[index+1:] for permutation in all_perms(other_elmts): yield [first_elmt] + permutation
The speed of the solution has increased by about 30%, obviously thanks to recursion with len (elements) < 1 instead of 0. Like Riccardo Reyes's solution, it uses generator functions (via yield), so it also improves memory efficiency.
#5 building
The following code is an in place arrangement of a given list, implemented as a generator. Since only references to the list are returned, the list should not be modified outside the generator. The solution is non recursive, so it uses low memory. Multiple copies of the elements in the input list also work well.
def permute_in_place(a): a.sort() yield list(a) if len(a) <= 1: return first = 0 last = len(a) while 1: i = last - 1 while 1: i = i - 1 if a[i] < a[i+1]: j = last - 1 while not (a[i] < a[j]): j = j - 1 a[i], a[j] = a[j], a[i] # swap the values r = a[i+1:last] r.reverse() a[i+1:last] = r yield list(a) break if i == first: a.reverse() return if __name__ == '__main__': for n in range(5): for a in permute_in_place(range(1, n+1)): print a print for a in permute_in_place([0, 0, 1, 1, 1]): print a print