Reputation: 43
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
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
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 inchar
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)]
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 asproduct(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)]
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:])
# 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