views:

9071

answers:

6

How do you generate all the permutations of a list in Python, independently of the type of elements in that 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]

EDIT: Eliben pointed to a solution that's similar to mine altough simpler, so I'm choosing it as the Accepted Answer, altough apparently Python 2.6 (that hasn't been released yet) will have a builtin solution in the itertools module:

import itertools
itertools.permutations([1,2,3])
+7  A: 

This solution implements a generator, to avoid holding all the permutations on 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
Ricardo Reyes
+14  A: 

See http://code.activestate.com/recipes/252178/:

def all_perms(str):
    if len(str) <=1:
        yield str
    else:
        for perm in all_perms(str[1:]):
            for i in range(len(perm)+1):
                #nb str[0:1] works in both string and list contexts
                yield perm[:i] + str[0:1] + perm[i:]
Eli Bendersky
This and other recursive solutions have a potential hazard of eating up all the RAM if the permutated list is big enough
bgbg
They also reach the recursion limit (and die) with large lists
dbr
+37  A: 

And in python 2.6:

import itertools
itertools.permutations([1,2,3])

(returned as a generator. Use list(permutations(l)) to return as a list.)

Brian
Works in Python 3 too
wheleph
+1  A: 

Forgive my python illiteracy as I won't be offering the solution in python. As I do not know what method python 2.6 uses to generate the permutations and eliben's one looks like Johnson-Trotter permutation generation, you might look for article in Wikipedia on Permutations and their generation that looks quite like unrank function in paper by Myrvold and Ruskey.

It would seem to me that this could be used in a generator in the same way as in other replies to lessen the memory requirement considerably. Just remember that the permutations will not be in lexicographic order.

Eonwe
+3  A: 

The following code is an in-place permutation of a given list, implemented as a generator. Since it only returns references to the list, the list should not be modified outside the generator. The solution is non-recursive, so uses low memory. Work well also with multiple copies of elements in the input list.

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
Ber
I made a slight improvement to the code - you can do an in-place swap with `x, y = y, x` - saves defining a function, and might make it marginally quicker
dbr
+10  A: 

The following code with Python 2.6 and above ONLY

First, import itertools:

import itertools

Permutation:

print list(itertools.permutations([1,2,3,4], 2))
[(1, 2), (1, 3), (1, 4),
(2, 1), (2, 3), (2, 4),
(3, 1), (3, 2), (3, 4),
(4, 1), (4, 2), (4, 3)]

Combination (order matters):

print list(itertools.combinations('123', 2))
[('1', '2'), ('1', '3'), ('2', '3')]

Cartesian product (with several iterables):

print list(itertools.product([1,2,3], [4,5,6]))
[(1, 4), (1, 5), (1, 6),
(2, 4), (2, 5), (2, 6),
(3, 4), (3, 5), (3, 6)]

Cartesian product (with one iterable and itself):

print list(itertools.product([1,2], repeat=3))
[(1, 1, 1), (1, 1, 2), (1, 2, 1), (1, 2, 2),
(2, 1, 1), (2, 1, 2), (2, 2, 1), (2, 2, 2)]

You can't iterate on a set so don't forget:

myset = set((1,2,3))
print myset
set([1, 2, 3])
myiterable = tuple(myset)
print myiterable
(1, 2, 3)
e-satis