Combinations with Replacement and maximal Occurrence Constraint

Question:

from itertools import *
import collections
for i in combinations_with_replacement(['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'],15):
    b = (''.join(i))
    freq = collections.Counter(b)
    for k in freq:
        if freq [k] < 5:
            print(k)

this code most print chars what count if less than 5

what i try do , cheek if at string from join at fly if there is repeated any of characters les than x times at any possition of that string and print strings only what true to that.

Problem is no mater what i try do , or its print all and ignore if … or print notting.
how do it right , or maybe at python exist simple solution ?

Result most be as example les than 5

False - fffaaffbbdd ( repeat 5 titemes f)
False - fffffaaaaac ( repeat 5 times a and f)
True -  aaabbbccc11 ( no any character repeated more than 4 times )

More clear explain qustion – filter all string with characters more than x repetions before give to next function.
As examble – there is simple print that strings , and not print strings what not at rule.

Asked By: tseries

||

Answers:

If I understand you right, you want to print strings where each character is found only 4-times at maximum:

from collections import Counter
from itertools import combinations_with_replacement


for i in combinations_with_replacement(['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'],15):
    c = Counter(i)
    if c.most_common(1)[0][1] > 4:
        continue
    print(''.join(i))

Prints:

...

00002446899cccd
00002446899ccce
00002446899cccf
00002446899ccdd

... 
Answered By: Andrej Kesely

a more constructive approach (meaning: i do not iterate over all possible combinations – i construct the valid combinations directly).

you need to have sympy installed for this to work.

in the example i only use the elements "abcdef" and restrict the repetitions to be strictly smaller than MAX = 4. i fix the length of the strings to be output at M = 6.

i start by getting all the partitions of M with restricted repetitions k=MAX - 1 and not constisting of more than m=N parts. i immediately convert those to a list:

{3: 2} [3, 3, 0, 0, 0, 0]
{3: 1, 2: 1, 1: 1} [3, 2, 1, 0, 0, 0]
{3: 1, 1: 3} [3, 1, 1, 1, 0, 0]
{2: 3} [2, 2, 2, 0, 0, 0]
{2: 2, 1: 2} [2, 2, 1, 1, 0, 0]
{2: 1, 1: 4} [2, 1, 1, 1, 1, 0]
{1: 6} [1, 1, 1, 1, 1, 1]

of those lists i iterate over the multiset permutations – i mean those to represent the elements that i select and how often they are repeated: e.g:

[2, 1, 2, 0, 0, 1] -> "aabccf"  # 2*"a", 1*"b", ..., 0*"e", 1*"f"

the result you want is then the multiset permutation of those strings.

from sympy.utilities.iterables import multiset_permutations, partitions

MAX = 4  # (all counts < MAX)
elements = "abcdef"
N = len(elements)
M = 6  # output length


def dict_to_list(dct, N):
    ret = [0] * N
    j = 0
    for k, v in dct.items():
        ret[j:j + v] = [k] * v
        j += v
    return ret


for dct in partitions(M, k=MAX - 1, m=N):
    lst = dict_to_list(dct, N)
    for part in multiset_permutations(lst):
        el = ''.join(n * v for n, v in zip(part, elements))
        for msp in multiset_permutations(el):
            print(''.join(msp))

for your case you’d then need to change:

MAX = 5  # (all counts < MAX)
elements = "0123456789abcdef"
M = 15  # output length

but the complexity of that is huge (but way better that the one of the original approach)!

Answered By: hiro protagonist