Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Permutation method in Python with some fixed elements

Having spent a considerable amount of time now trying to come up with a way to (what I think) should be a relatively simple procedure, I have managed to write the code which will generate the results (thanks to suggestions on this wonderful forum!), but according to my calculations it would take several years to compute all possibilities, so I'm desperately looking for some help as I fear my computer may not live to see that day. :) Any input would be very much appreciated!

What I would like to achieve is from a list of 10 unique entries (e.g. ['A','B','C','D','E','F','G',H','I','J']), get all permutations over a string length of 10, but with the requirement that 1 of the elements (e.g. 'C'), should occur exactly 3 times, and in all possible locations.

Right now I am using:

options = ['A','B','C','D','E','F','G','H','I','J']
def combos(options,n):
    if (n <= 0): return
    for s in options:
        if len(s) <= n: yield s
        for t in combos(options,n-len(s)): yield s+t

for x in combos(options,10):
    if x.count("C") == 3 and len(x) == 10:
        print x

This way, it is computing all possible permutations and picks the ones with 3 'Cs', and therefore generates a large amount of unnecessary permutations which do not contain 3 'Cs', hence why it is taking longer than necessary. Does anyone have any suggestions how I might get Python to adhere to the 3x 'C' restriction while generating the permutations?

many, many thanks in advance!

like image 451
les_paulde Avatar asked Dec 26 '22 18:12

les_paulde


2 Answers

The simplest way would be to generate permutations of 7 elements using the other letters, then interleave three Cs in with this afterwards.

like image 119
BrenBarn Avatar answered Dec 29 '22 08:12

BrenBarn


itertools is your friend:

from itertools import chain, imap, permutations, combinations, repeat
others = [o for o in options if o != 'C']
chain.from_iterable(permutations(*chain(repeat('C', 3), x))
                    for x in combinations(others, 7))

Edit: this will give permutations, not combinations; if you want the result to be AAAAAAACCC .. CCCJJJJJJJ then it'll have to be slightly different. Here's a reasonably efficient product/filter solution:

from itertools import product
(x for x in product(options, repeat=10) if x.count('C') == 3)

And here's a method using interleaving as suggested by BrenBarn:

from itertools import product
others = [o for o in options if o != 'C']
(r[:i] + ('C',) + r[i:j] + ('C',) + r[j:k] + ('C',) + r[k:]
 for r in product(others, repeat=7)
 for i in range(8) for j in range(i, 8) for k in range(j, 8))

You'll need to test yourself, but for me the interleave method was significantly faster.

like image 28
ecatmur Avatar answered Dec 29 '22 09:12

ecatmur