Permutation over a list with selected elements
Alex Martelli
aleax at mac.com
Wed Jun 20 00:37:54 EDT 2007
weidongtom at gmail.com <weidongtom at gmail.com> wrote:
> Hi,
>
> I have been working at this problem, and I think I need a permutation
> algorithm that does
> the following:
>
> 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']
>
> Can anyone help me out? Thanks in advance.
I would proceed in 2 steps:
1. find all the sets of indices that are to be permuted
2. produce all the permutations given said sets
Now (1) is pretty easy:
import collections
def find_sets_of_indices_to_permute(L):
set_by_letter = collections.defaultdict(list)
for i, elem in enumerate(L):
if len(elem)>1:
set_by_letter[elem[0]].append(i)
return set_by_letter.values()
For (2), it looks like we need 2 sub-steps:
2.1. do all permutations of a list given ONE set of indices to permute
2.2. apply the function sub (2.1) to all the sets of indices to permute
let's do 2.1 the lazy way, i.e., recursively:
def all_permutations_given_indices(L, indices):
yield L
if len(indices) < 2:
return
x = indices.pop()
pivot = L[x]
for y in indices:
L[x] = L[y]
L[y] = pivot
for permut in all_permutations_given_indices(L, indices):
yield permut
L[y] = L[x]
L[x] = pivot
indices.append(x)
This suggests doing 2.2 recursively as well:
def all_permutations_with_constraints(L, constraints):
if len(constraints) == 1:
for p in all_permutations_given_indices(L, constraints[0]):
yield L
return
indices = constraints.pop()
for p in all_permutations_given_indices(L, indices):
for pp in all_permutations_with_constraints(p, constraints):
yield pp
constraints.append(indices)
and, putting it all together:
def do_it_all(L):
sets_of_indices = find_sets_of_indices_to_permute(L)
for p in all_permutations_with_constraints(L, sets_of_indices):
print p
Applied to your example list, this gives:
brain:~ alex$ python cp.py
['a', 'b', 'c1', 'd', 'e1', 'f', 'c2', 'x', 'e2']
['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']
Warning: untested beyond this single run, and _definitely_ not optimal
in either clarity, style, or speed -- just a quick hack to get you
started.
Alex
More information about the Python-list
mailing list