All permutations of a list
Alex Martelli
aleaxit at yahoo.com
Fri Oct 27 07:55:26 EDT 2000
"Richard van de Stadt" <stadt at cs.utwente.nl> wrote in message
news:39F8A95B.F34978F8 at cs.utwente.nl...
[snip]
> Rainer Deyke wrote:
> > Here's my short Pythonic permutation function:
> >
> > def perms(list):
> > if list == []:
> > return [[]]
> > return [[list[i]] + p for i in range(len(list))\
> > for p in perms(list[:i] + list[i+1:])]
>
> My collegue found another Miranda/Amanda solution, which looks
> similar (or is it _the_ equivalent?)
>
> perms [] = [[]]
> perms l = [ x:p | x <- l ; p <- perms (l--[x]) ]
>
> x <- l: x walks through all values of l
> for every x, p is set to all permutations of l_without_x
> x:p means x with p appended.
I think a closer Python equivalent would be (mimicking
the Miranda variable names too):
def perms(l):
if l == []: return [[]]
return [ [x]+p for x in l for p in perms( remove(l,x) ) ]
except that Python has no built-in way to return a _copy_
of a list with certain alterations (except for the append
operator), so the remove function should also be supplied:
def remove(l,x):
l=l[:]
l.remove(x)
return l
Rainer's solution, by iterating on indices rather than on
list-contents, manages to achieve the desired result (get a
list like l, except it's without element x, without altering
l itself) -- except it arguably does it better, since it
behaves quite well even if the input list has duplicates
(I'm not sure about the semantics of Miranda's --... what
happens if the list has more than one occurrence of x...?).
I.e., Rainer's version acts on lists-with-duplicates "just
as if" the duplicate elements were 'invisibly tagged' so
as to be distinguishable; my version gives a different
ordering if duplicates are present (since it's always the
*first* occurrence that gets removed).
An interesting variation, thinking of lists with duplicate
elements allowed, is to produce only the *distinguishable*
permutations (i.e. have a permutations-list that does NOT
have duplicates itself, though the base-list does). I
think all it takes is adding a guard, to handle only those
elements that are their first occurrence in the list, i.e.,
for Rainer's version:
def perms(list):
if list == []:
return [ [] ]
return [ [list[i]] + p
for i in range(len(list))
if i == list.index(list[i])
for p in perms(list[:i]+list[i+1:]) ]
Alex
More information about the Python-list
mailing list