# -*- coding: utf-8 -*-
# Python 2.7
'''From here: http://stackoverflow.com/questions/4250125/generate-permutations-of-list-with-repeated-elements
and here: http://b...content-available-to-author-only...n.se/2008/04/lexicographic-permutations-using.html
This version is 3.5 times slower than the version working directly with indexes'''
from __future__ import print_function
from itertools import izip
def lexicographic_permutations(seq):
"""Algorithm L for The Art of Computer Programming, Volume 4, Fascicle 2: Generating All Tuples and Permutations."""
def reverse(seq, start, end):
'''In-place reversion. Start and end denote the indexes of the last and the first element'''
while start < end:
seq[start], seq[end] = seq[end], seq[start]
start += 1
end -= 1
def pairwise_reversed_enumerated(L):
"(a,b,c,d) -> ((2,c),(3,d)), ((1,b),(2,c)), ((0,a),(1,b))"
length = len(L)
a1 = izip(xrange(length-1,-1,-1),reversed(L))
a2 = izip(xrange(length-1,-1,-1),reversed(L))
next(a1, None)
return izip(a1, a2)
def reversed_enumerated(L):
'(a,b,c,d) -> (3,d), (2,c), (1,b), (0,a)'
return izip(xrange(len(L)-1,-1,-1),reversed(L))
#[Some checks]
if not seq:
raise StopIteration
try:
seq[0]
except TypeError:
raise TypeError("seq must allow random access.")
#[end checks]
last = len(seq)-1
seq = seq[:] #copy the input sequence
yield seq #return the seq itself as a first value
while True:
for ((i1,a1),(i2,a2)) in pairwise_reversed_enumerated(seq):
if a1 < a2:
for (l,val) in reversed_enumerated(seq):
if a1 < val:
seq[i1], seq[l] = seq[l], seq[i1]
break
reverse(seq, i2, last)
yield seq[:] # Change to yield references to get rid of (at worst) |seq|! copy operations.
break
else: #this part will only run when there were no 'break' inside the for-loop
break #at this position there is no a1<a2, so we have reached the finish, so breaking out of the outer loop
if __name__ == '__main__':
import timeit
#use 'pass' instead of 'print(p)' to get rid of hefty print function time complexity charges.
t = timeit.Timer(stmt='for p in lexicographic_permutations(range(9)): pass',setup='from __main__ import lexicographic_permutations')
print(t.timeit(number=1))
IyAtKi0gY29kaW5nOiB1dGYtOCAtKi0KIyBQeXRob24gMi43CicnJ0Zyb20gaGVyZTogaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy80MjUwMTI1L2dlbmVyYXRlLXBlcm11dGF0aW9ucy1vZi1saXN0LXdpdGgtcmVwZWF0ZWQtZWxlbWVudHMKYW5kIGhlcmU6IGh0dHA6Ly9iLi4uY29udGVudC1hdmFpbGFibGUtdG8tYXV0aG9yLW9ubHkuLi5uLnNlLzIwMDgvMDQvbGV4aWNvZ3JhcGhpYy1wZXJtdXRhdGlvbnMtdXNpbmcuaHRtbApUaGlzIHZlcnNpb24gaXMgMy41IHRpbWVzIHNsb3dlciB0aGFuIHRoZSB2ZXJzaW9uIHdvcmtpbmcgZGlyZWN0bHkgd2l0aCBpbmRleGVzJycnCgpmcm9tIF9fZnV0dXJlX18gaW1wb3J0IHByaW50X2Z1bmN0aW9uCmZyb20gaXRlcnRvb2xzIGltcG9ydCBpemlwCgoKZGVmIGxleGljb2dyYXBoaWNfcGVybXV0YXRpb25zKHNlcSk6CiAgICAiIiJBbGdvcml0aG0gTCBmb3IgVGhlIEFydCBvZiBDb21wdXRlciBQcm9ncmFtbWluZywgVm9sdW1lIDQsIEZhc2NpY2xlIDI6IEdlbmVyYXRpbmcgQWxsIFR1cGxlcyBhbmQgUGVybXV0YXRpb25zLiIiIgoKICAgIGRlZiByZXZlcnNlKHNlcSwgc3RhcnQsIGVuZCk6CiAgICAgICAgJycnSW4tcGxhY2UgcmV2ZXJzaW9uLiBTdGFydCBhbmQgZW5kIGRlbm90ZSB0aGUgaW5kZXhlcyBvZiB0aGUgbGFzdCBhbmQgdGhlIGZpcnN0IGVsZW1lbnQnJycKICAgICAgICAKICAgICAgICB3aGlsZSBzdGFydCA8IGVuZDoKICAgICAgICAgICAgc2VxW3N0YXJ0XSwgc2VxW2VuZF0gPSBzZXFbZW5kXSwgc2VxW3N0YXJ0XQogICAgICAgICAgICBzdGFydCArPSAxCiAgICAgICAgICAgIGVuZCAtPSAxCgoKICAgIGRlZiBwYWlyd2lzZV9yZXZlcnNlZF9lbnVtZXJhdGVkKEwpOgogICAgICAgICIoYSxiLGMsZCkgLT4gKCgyLGMpLCgzLGQpKSwgKCgxLGIpLCgyLGMpKSwgKCgwLGEpLCgxLGIpKSIKICAgICAgICBsZW5ndGggPSBsZW4oTCkKICAgICAgICBhMSA9IGl6aXAoeHJhbmdlKGxlbmd0aC0xLC0xLC0xKSxyZXZlcnNlZChMKSkKICAgICAgICBhMiA9IGl6aXAoeHJhbmdlKGxlbmd0aC0xLC0xLC0xKSxyZXZlcnNlZChMKSkKICAgICAgICBuZXh0KGExLCBOb25lKQogICAgICAgIHJldHVybiBpemlwKGExLCBhMikKCgogICAgZGVmIHJldmVyc2VkX2VudW1lcmF0ZWQoTCk6CiAgICAgICAgJyhhLGIsYyxkKSAtPiAoMyxkKSwgKDIsYyksICgxLGIpLCAoMCxhKScKICAgICAgICByZXR1cm4gaXppcCh4cmFuZ2UobGVuKEwpLTEsLTEsLTEpLHJldmVyc2VkKEwpKQoKCiAgICAjW1NvbWUgY2hlY2tzXQogICAgaWYgbm90IHNlcToKICAgICAgICByYWlzZSBTdG9wSXRlcmF0aW9uCgogICAgdHJ5OgogICAgICAgIHNlcVswXQogICAgZXhjZXB0IFR5cGVFcnJvcjoKICAgICAgICByYWlzZSBUeXBlRXJyb3IoInNlcSBtdXN0IGFsbG93IHJhbmRvbSBhY2Nlc3MuIikKICAgICNbZW5kIGNoZWNrc10KCiAgICBsYXN0ID0gbGVuKHNlcSktMQogICAgc2VxID0gc2VxWzpdICNjb3B5IHRoZSBpbnB1dCBzZXF1ZW5jZQogICAgCiAgICB5aWVsZCBzZXEgI3JldHVybiB0aGUgc2VxIGl0c2VsZiBhcyBhIGZpcnN0IHZhbHVlCgogICAgd2hpbGUgVHJ1ZToKICAgICAgICBmb3IgKChpMSxhMSksKGkyLGEyKSkgaW4gcGFpcndpc2VfcmV2ZXJzZWRfZW51bWVyYXRlZChzZXEpOgogICAgICAgICAgICBpZiBhMSA8IGEyOgogICAgICAgICAgICAgICAgZm9yIChsLHZhbCkgaW4gcmV2ZXJzZWRfZW51bWVyYXRlZChzZXEpOgogICAgICAgICAgICAgICAgICAgIGlmIGExIDwgdmFsOgogICAgICAgICAgICAgICAgICAgICAgICBzZXFbaTFdLCBzZXFbbF0gPSBzZXFbbF0sIHNlcVtpMV0KICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWsKICAgICAgICAgICAgICAgIHJldmVyc2Uoc2VxLCBpMiwgbGFzdCkKICAgICAgICAgICAgICAgIHlpZWxkIHNlcVs6XSAjIENoYW5nZSB0byB5aWVsZCByZWZlcmVuY2VzIHRvIGdldCByaWQgb2YgKGF0IHdvcnN0KSB8c2VxfCEgY29weSBvcGVyYXRpb25zLgogICAgICAgICAgICAgICAgYnJlYWsKICAgICAgICBlbHNlOiAjdGhpcyBwYXJ0IHdpbGwgb25seSBydW4gd2hlbiB0aGVyZSB3ZXJlIG5vICdicmVhaycgaW5zaWRlIHRoZSBmb3ItbG9vcAogICAgICAgICAgICBicmVhayAjYXQgdGhpcyBwb3NpdGlvbiB0aGVyZSBpcyBubyBhMTxhMiwgc28gd2UgaGF2ZSByZWFjaGVkIHRoZSBmaW5pc2gsIHNvIGJyZWFraW5nIG91dCBvZiB0aGUgb3V0ZXIgbG9vcAogICAgICAgIAoKaWYgX19uYW1lX18gPT0gJ19fbWFpbl9fJzoKICAgIGltcG9ydCB0aW1laXQKICAgICN1c2UgJ3Bhc3MnIGluc3RlYWQgb2YgJ3ByaW50KHApJyB0byBnZXQgcmlkIG9mIGhlZnR5IHByaW50IGZ1bmN0aW9uIHRpbWUgY29tcGxleGl0eSBjaGFyZ2VzLgogICAgdCA9IHRpbWVpdC5UaW1lcihzdG10PSdmb3IgcCBpbiBsZXhpY29ncmFwaGljX3Blcm11dGF0aW9ucyhyYW5nZSg5KSk6IHBhc3MnLHNldHVwPSdmcm9tIF9fbWFpbl9fIGltcG9ydCBsZXhpY29ncmFwaGljX3Blcm11dGF0aW9ucycpCiAgICBwcmludCh0LnRpbWVpdChudW1iZXI9MSkpCiAgICAKICAgIAo=