264124475f095b65634c53da3380b88d

I suspect there is a better way to deal with the end of the sequence.

#!/usr/bin/python2.5
def permute(li):
    """Generate all permutations of a sequence
    >>> for i in permute([1,2,3]): print i
    (1, 2, 3)
    (1, 3, 2)
    (2, 1, 3)
    (2, 3, 1)
    (3, 1, 2)
    (3, 2, 1)"""
    return ((i,)+j for i in li for j in (permute([k for k in li if k is not i])
                                         if len(li) > 1 else [()] ) )

import doctest
doctest.testmod(verbose=True)

Refactorings

No refactoring yet !

C2953d47b6de83f3217b48c3584fab1c

Auron

October 22, 2008, October 22, 2008 08:20, permalink

No rating. Login to rate!

Your code works great but addresses a different problem than this one (http://refactormycode.com/codes/523-permutation-of-values), which is really not a permutation (it was my fault).

I like your one-line solution, although I find it difficult to understand :)

Dd1696879621083cb32811a3b8926cd2

William Bowers

October 30, 2008, October 30, 2008 07:29, permalink

No rating. Login to rate!

First off let me say your solution is already an elegant one. I only made one change: I shortened your list comprehension (or I guess in this case, generator comprehension) by making use of a sort of ternary operator hack; if you don't already know, placing a boolean value as an index for a tuple will evaluate to 1 if True and 0 if False. Thus ("foo", "bar")[False] evaluates to "foo" and ("foo", "bar")[True] evaluates to "bar".

Nice work though :) took me a minute to understand the logic behind this one.

#!/usr/bin/python2.5                                                                                     

def permute(li):
    return ((i,)+j for i in li for j in (([()], permute([k for k in li if k is not i]))[len(li) > 1]))

for i in permute([1, 2, 3]):
    print i
264124475f095b65634c53da3380b88d

Leif Ryge

October 30, 2008, October 30, 2008 20:23, permalink

No rating. Login to rate!

Thanks! I was actually unaware that booleans could be used as getitem keys, which is a very useful trick. I wonder why I've seen this ugly idiom A in wide use instead of the much more elegant B:

idiom_A = lambda x,y,z: (x and [y] or [z])[0]
idiom_B = lambda x,y,z: (z, y)[x]
idiom_C = lambda x,y,z: y if x else z # introduced in Python 2.5
264124475f095b65634c53da3380b88d

Leif Ryge

October 31, 2008, October 31, 2008 06:55, permalink

1 rating. Login to rate!

Answering my own question: the caveat to idiom_B is that it isn't short-circuiting. So, if instead of z and y we had z() and y() then evaluating the expression causes BOTH functions to be called (regardless of the value of x) in idiom_B, while in A and C only the desired function is called.

Dd1696879621083cb32811a3b8926cd2

William Bowers

October 31, 2008, October 31, 2008 20:41, permalink

No rating. Login to rate!

That's very true. In this case it would be better to go with A, as you probably don't want that last call to permute() to go off. I prefer B in case where it doesn't really matter, like when Z and Y are both strings or numbers, or when both Z and Y need to go off anyway. Either way works, A is faster :)

D41d8cd98f00b204e9800998ecf8427e

Gabriele

March 15, 2010, March 15, 2010 23:03, permalink

No rating. Login to rate!
import itertools
itertools.permutations([1,2,3],3)

Your refactoring





Format Copy from initial code

or Cancel