permpyt
permpyt

Reputation: 43

All combinations by changing 3 places

Here's the code

from itertools import combinations, product

string = "abcd012345"

char = "01268abc"

for i, j in combinations(tuple(range(len(string))), 2):
    for char1, char2 in product(char, char):
        print(string[:i] + char1 + string[i+1:j] + char2 + string[j+1:])

We have a string abcd012345 , we change two places in order to get all possible combinations. In this example we use char a set of characters that can be used.

The goal is to change 2 for 3 in order to replace 3 places with replacement and find all possible combinations by changing 3 places.

Will enjoy to learn from your solution, thank you.

Upvotes: 0

Views: 135

Answers (2)

Alain T.
Alain T.

Reputation: 42133

This is going to print thousands of strings. You may also want to consider if you're looking for distinct output strings or just raw combinations:

The solution is merely a generalization of your 2-character approach where fixed sized logic is made variable based on a parameter.

from itertools import combinations,product

def replaceCombo(string,char,count):
    for positions in combinations(range(len(string)),count):
        for characters in product(char,repeat=count):
            newString=list(string)
            for p,c in zip(positions,characters):
                newString[p]=c
            yield "".join(newString)


string = "abcd012345"
char   = "01268abc"
for newString in replaceCombo(string,char,2): print(newString)

00cd012345
01cd012345
02cd012345
06cd012345
... total 2,880 strings

print(len(set(replaceCombo(string,char,2)))) # 2,538 distinct strings

for newString in replaceCombo(string,char,3): print(newString)
000d012345
001d012345
002d012345
006d012345
008d012345
00ad012345
... total 61,440 strings

print(len(set(replaceCombo(string,char,3)))) # 51,094 distinct strings

Upvotes: 0

lucidbrot
lucidbrot

Reputation: 6168

Let us first discuss what you are doing right now and then we build a similar solution. As you clarified in a comment, your end goal is to

compute all possible ways you could replace exactly three characters in string with characters in char

Outer Loop

You do combinations(tuple(range(len(string))), 2). So first you make a tuple containing all the values from 0 to len(string) and then you generate all the possible combinations consisting of two values from that tuple. It's not necessary to use tuple() here. According to the docs the second parameter of combinations is how many times it should pick a value for building one single result. Also in the docs we can find the information that combinations will not reuse values for the resulting tuples.

So we can modify this to

for i, j, k in combinations(range(len(string)), 3)
# generates tuples like this:
# >>> list(combinations(range(4), 3))
# [(0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3)]

Inner Loop

You pick two characters from char. This time, according to the docs it's equivalent to ((x,y) for x in A for y in B). Notice that the docs show that there is a second, optional, parameter:

To compute the product of an iterable with itself, specify the number of repetitions with the optional repeat keyword argument. For example, product(A, repeat=4) means the same as product(A, A, A, A).

So we can use for char1, char2, char3 in product(char, repeat=3). As you can see in the following example, this time there are repetitions.

list(product([1,2,3,4], repeat=3))
[(1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 1, 4), (1, 2, 1), (1, 2, 2), (1, 2, 3), (1, 2, 4), (1, 3, 1), (1, 3, 2), (1, 3, 3), (1, 3, 4), (1, 4, 1), (1, 4, 2), (1, 4, 3), (1, 4, 4), (2, 1, 1), (2, 1, 2), (2, 1, 3), (2, 1, 4), (2, 2, 1), (2, 2, 2), (2, 2, 3), (2, 2, 4), (2, 3, 1), (2, 3, 2), (2, 3, 3), (2, 3, 4), (2, 4, 1), (2, 4, 2), (2, 4, 3), (2, 4, 4), (3, 1, 1), (3, 1, 2), (3, 1, 3), (3, 1, 4), (3, 2, 1), (3, 2, 2), (3, 2, 3), (3, 2, 4), (3, 3, 1), (3, 3, 2), (3, 3, 3), (3, 3, 4), (3, 4, 1), (3, 4, 2), (3, 4, 3), (3, 4, 4), (4, 1, 1), (4, 1, 2), (4, 1, 3), (4, 1, 4), (4, 2, 1), (4, 2, 2), (4, 2, 3), (4, 2, 4), (4, 3, 1), (4, 3, 2), (4, 3, 3), (4, 3, 4), (4, 4, 1), (4, 4, 2), (4, 4, 3), (4, 4, 4)]

Loop Content

What you finally do here is printing the string except for the positions where you want to replace characters. You use the characters from the inner loop and the positions from the outer loop. So effectively, for every two characters (including repetitions) you print a string for every possible way of positioning them (without repetitions, because you can't place them both at the same place).

Since we have now modified the loops to generate three positions and three characters, we only need to add the third modification.

It seems like we're in luck: combinations only generates the position tuples in ascending order. So we can assume that i < j < k.

print(string[:i] + char1 + string[i+1:j] + char2 + string[j+1:k] + char3 + string[k+1:])

Putting It All Together

# same as before
from itertools import combinations, product
string = "abcd012345"
char = "01268abc"

# modified as explained above
for i, j, k in combinations(range(len(string)), 3):
  for char1, char2, char3 in product(char, repeat=3):
    print(string[:i] + char1 + string[i+1:j] + char2 + string[j+1:k] + char3 + string[k+1:])

Upvotes: 2

Related Questions