poppyseeds
poppyseeds

Reputation: 451

Change one character at a time in a string, don't change the string?

I have a string:

'ABCDEFGH'

I want to cycle through the string and, one by one, replace each character with one of 4 characters (1,2,3,4):

'ABCDEFGH'
'1BCDEFGH'
'A1CDEFGH'
'AB1DEFGH'

etc

'2BCDEFGH'
'A2CDEFGH'
'AB2DEFGH'

etc and so forth. However everytime I try, I end up altering the original string and my output ends up being strings of 1s!

'1111111'

Example code below:

letters = 'ABCDEFGH'

s = list(letters)
y = 0 
while y < len(s): 
   s[y] = '1'
   y = y + 1

Upvotes: 0

Views: 992

Answers (3)

Martijn Pieters
Martijn Pieters

Reputation: 1121356

Rather than change a list you reuse between iterations, produce a new list each time and replace the one character:

for i in range(len(letters)):
    s = list(letters)
    s[i] = '1'
    print(''.join(s))

You can combine this with a nested loop:

for digit in '1234':
    for i in range(len(letters)):
        s = list(letters)
        s[i] = digit
        print(''.join(s))

In essence you are creating the product of '1234' and a position from range(len(letters)), so you could use itertools.product() to make that a single loop:

from itertools import product

for digit, pos in product('1234', range(len(letters))):
    s = list(letters)
    s[pos] = digit
    print(''.join(s))

With a little enumerate() trickery you could make this a one-liner generator expression to produce all combinations:

from itertools import product

all_combos = (
    ''.join([digit if i == pos else c for i, c in enumerate(letters)])
    for digit, pos in product('1234', range(len(letters))))

This builds a new list on the fly by iteration over letters, swapping out the one character at position pos for the digit.

Demo:

>>> from itertools import product
>>> letters = 'ABCDEFGH'
>>> all_combos = (
...     ''.join([digit if i == pos else c for i, c in enumerate(letters)])
...     for digit, pos in product('1234', range(len(letters))))
>>> 
>>> next(all_combos)
'1BCDEFGH'
>>> next(all_combos)
'A1CDEFGH'
>>> next(all_combos)
'AB1DEFGH'
>>> next(all_combos)
'ABC1EFGH'
>>> from itertools import islice
>>> print(list(islice(all_combos, 10)))
['ABCD1FGH', 'ABCDE1GH', 'ABCDEF1H', 'ABCDEFG1', '2BCDEFGH', 'A2CDEFGH', 'AB2DEFGH', 'ABC2EFGH', 'ABCD2FGH', 'ABCDE2GH']

Upvotes: 3

Loupi
Loupi

Reputation: 580

string = 'ABCDEFG'
dig = []

for i in range(1,8):
    dig.append(str(i))
    for letter in string[:]:
        print string.replace(letter,dig[i-1])

Upvotes: 0

Ignacio Vazquez-Abrams
Ignacio Vazquez-Abrams

Reputation: 798526

Reinitialize the list each time.

while y < len(letters):
  s = list(letters)
  s[y] = '1'
  y = y + 1
  dosomethingwith(s)

Upvotes: 0

Related Questions