user2061944 user2061944 - 4 months ago 14
Python Question

Create variations of a string

I generated random strings of 16-characters each and added them to a list using the following:

import random
strings = []
for x in range(0, 99):
strings.append(''.join(random.choice('0123456789ABCDEF') for i in range(16)))


This worked as expected. Now, for each generated string, I want to find all possible combinations such that at least two characters remain same as the original string and the order of characters does not change. For example, if we have CDD733665417E3F1, then I want to generate all CDXXXXXXXXXXXXXX where X could be anything (0-9 or A-F). Similarly XXD7XXXXXXXXXXXX and so on. Previous similar questions hint towards using
itertools.product
but I am not sure how it can be used to generate permutations and not fixed replacements. Any help will be appreciated. Thank you

Answer

Create an iterator for the indices of the two characters you want to stay the same using itertools.combinations

>>> from itertools import combinations
>>> s = 'ABC123'
>>> for indices in combinations(range(len(s)), 2):
...     print ''.join([s[x] if x in indices else 'X' for x in range(len(s))])
...
ABXXXX
AXCXXX
AXX1XX
AXXX2X
AXXXX3
XBCXXX
XBX1XX
XBXX2X
XBXXX3
XXC1XX
XXCX2X
XXCXX3
XXX12X
XXX1X3
XXXX23

Creates all the variable strings.

You can then do a nested loop to replace the X's.

Then you can use product to get all the letters that you would need to replace the X's with:

>>> for letters in product('ABCDEF0123456789', repeat = 4):
...     print letters
...
('A', 'A', 'A', 'A')
('A', 'A', 'A', 'B')
('A', 'A', 'A', 'C')
('A', 'A', 'A', 'D')
('A', 'A', 'A', 'E')
('A', 'A', 'A', 'F')
('A', 'A', 'A', '0')
('A', 'A', 'A', '1')
('A', 'A', 'A', '2')
('A', 'A', 'A', '3')
('A', 'A', 'A', '4')
('A', 'A', 'A', '5')
('A', 'A', 'A', '6')
('A', 'A', 'A', '7')
('A', 'A', 'A', '8')
('A', 'A', 'A', '9')
('A', 'A', 'B', 'A')
('A', 'A', 'B', 'B')
('A', 'A', 'B', 'C')
('A', 'A', 'B', 'D')
('A', 'A', 'B', 'E')
('A', 'A', 'B', 'F')
('A', 'A', 'B', '0')
('A', 'A', 'B', '1')
('A', 'A', 'B', '2')
.
.
.

Combine these together and you would get all the combinations of what you want.

You can probably do something like:

>>> for indices in combinations(range(len(s)), 2):
...     for letters in product('ABCDEF0123456789', repeat = 4):
...          letter_iter = iter(letters)
...          print ''.join([s[x] if x in indices else letter_iter.next() for x in range(len(s))])

NOTE 1: you can change the 2 in the call of combinations to change the amount of indices you want to stay the same. Likewise, you can change the repeat parameter in the call to product to reflect those changes (repeat = n where n = len(s) - number_in_combinations)

NOTE 2: These are stupidly large amounts of values. You know this. Please be careful that you don't destroy your memory. When I did the product call, I added an index counter and broke the loop after the index counter got greater than 20 to avoid hell breaking loose.