Fast generation of permutations

Michael Amrhein michael at adrhinum.de
Wed Jan 25 12:03:35 EST 2006


Michael Amrhein schrieb:
> Frode Øijord schrieb:
>> Hi all,
>> given a sequence of n elements i need to generate all possible 
>> permutations of length k <= n.
>>
>> I found an elegant way to do this recursively:
>>
>> def comb(items, n):
>>     if n==0: yield []
>>     else:
>>         for i in xrange(len(items)):
>>             for cc in comb(items[i+1:],n-1):
>>                 yield [items[i]]+cc
>>
>> However, this is way too slow for my needs. I try to use this to 
>> generate all possible 5 card poker hands, but this takes around 17 
>> seconds on an Athlon 2200. That's a 2 orders of magnitude too slow for 
>> my needs.
>>
>> I am familiar with writing Python extensions in C++, but I will not do 
>> this until I am confident that it is the only way to get the speed I 
>> need.
>>
>> Any of you excellent sirs have any suggestions on how I can speed this 
>> up?
>>
>> Please find attached an example script that executes and times the 
>> poker hand generation.
>>
>>
>>
>> ------------------------------------------------------------------------
>>
>> import sys
>> from timeit import Timer
>>
>> def comb(items, n):
>>     if n==0: yield []
>>     else:
>>         for i in xrange(len(items)):
>>             for cc in comb(items[i+1:],n-1):
>>                 yield [items[i]]+cc
>>
>>
>> def test():
>>     cards = range(52)
>>     for hand in comb(cards, 5):
>>         "do something with the hand"       
>> def main(argv):
>>     t = Timer("test()", "from __main__ import test")
>>     print t.timeit(1)
>>
>>
>> if __name__=="__main__":
>>     sys.exit(main(sys.argv[1:]))
> 
> If you don't need the flexibility of having the number of elements in 
> your permutation as a parameter - as it seems to be the case in your 
> poker example - simply use nested for-loops, 5 in this case.
> Example for 5 out of 7 (just to keep the output shorter):
> for i1 in range(7):
>     for i2 in range(i1+1,7):
>         for i3 in range(i2+1,7):
>             for i4 in range(i3+1,7):
>                 for i5 in range(i4+1,7):
>                     print i1,i2,i3,i4,i5
> 
> 0 1 2 3 4
> 0 1 2 3 5
> 0 1 2 3 6
> 0 1 2 4 5
> 0 1 2 4 6
> 0 1 2 5 6
> 0 1 3 4 5
> 0 1 3 4 6
> 0 1 3 5 6
> 0 1 4 5 6
> 0 2 3 4 5
> 0 2 3 4 6
> 0 2 3 5 6
> 0 2 4 5 6
> 0 3 4 5 6
> 1 2 3 4 5
> 1 2 3 4 6
> 1 2 3 5 6
> 1 2 4 5 6
> 1 3 4 5 6
> 2 3 4 5 6
> 
> Have fun
> Michael
Even faster:
 >>>[(i1,i2,i3,i4,i5) for i1 in range(7) for i2 in range(i1+1,7) for i3 
in range(i2+1,7) for i4 in range(i3+1,7) for i5 in range(i4+1,7)]
[(0, 1, 2, 3, 4), (0, 1, 2, 3, 5), (0, 1, 2, 3, 6), (0, 1, 2, 4, 5), (0, 
1, 2, 4, 6), (0, 1, 2, 5, 6), (0, 1, 3, 4, 5), (0, 1, 3, 4, 6), (0, 1, 
3, 5, 6), (0, 1, 4, 5, 6), (0, 2, 3, 4, 5), (0, 2, 3, 4, 6), (0, 2, 3, 
5, 6), (0, 2, 4, 5, 6), (0, 3, 4, 5, 6), (1, 2, 3, 4, 5), (1, 2, 3, 4, 
6), (1, 2, 3, 5, 6), (1, 2, 4, 5, 6), (1, 3, 4, 5, 6), (2, 3, 4, 5, 6)]
Michael



More information about the Python-list mailing list