Permutation over a list with selected elements
Anton Vredegoor
anton.vredegoor at gmail.com
Wed Jun 20 18:49:40 EDT 2007
weidongtom at gmail.com wrote:
> Given a list of elements that are either a character or a character
> follows by a number, e.g.
>
> ['a', 'b', 'c1', 'd', 'e1', 'f', 'c2', 'x', 'e2']
>
> find all the permutations that are given by switching the positions of
> the elements that:
> (1) begins with the same letter, and
> (2) follows by a number.
>
> With the above list, some possible permutations are:
>
> ['a', 'b', 'c2', 'd', 'e1', 'f', 'c1', 'x', 'e2']
> ['a', 'b', 'c1', 'd', 'e2', 'f', 'c2', 'x', 'e1']
> ['a', 'b', 'c2', 'd', 'e2', 'f', 'c1', 'x', 'e1']
Another idea, untested. Also I am not sure whether sequences types are
supposed to be returning functions ...
A.
from operator import mul
from collections import defaultdict
class Swapper:
"""
Given a set of indices this class returns functions
which will swap elements in a list *in place*.
Each function corresponds to a permutation of the
set of indices.
"""
def __init__(self,L):
self.L = L
self.n = reduce(mul,range(2,len(L)+1),1) #faculty
def __getitem__(self,i):
L = self.L
if not -1<i<self.n:
raise IndexError
def func(R):
Q = perm([R[j] for j in L],i)
for j,x in zip(L,Q):
R[j] = x
return func
def perm(L,m):
#permutation m of list L
res = []
T = L[::-1]
for i in range(len(L),0,-1):
res.append(T.pop(m%i))
m /= i
return res[::-1]
def cross(args):
#Raymond Hettinger's cross product function from ASPN
ans = [[]]
for arg in args:
ans = [x+[y] for x in ans for y in arg]
return ans
def find_sets_of_indices_to_permute(L):
set_by_letter = defaultdict(list)
for i, elem in enumerate(L):
if len(elem)>1:
set_by_letter[elem[0]].append(i)
return set_by_letter.values()
def test():
L = ['a', 'b', 'c1', 'd', 'e1', 'f', 'c2', 'x', 'e2']
I = find_sets_of_indices_to_permute(L) #Alex Martelli's function
M = map(Swapper,I)
for F in cross(M):
# conserve the original list because
#the functions modify a list in place
R = list(L)
# apply each permutation function one by one,
# each is acting on a different set of indices
for fn in F:
fn(R)
print R
if __name__=='__main__':
test()
More information about the Python-list
mailing list