1

Suppose I have a string value str=xxx. Now I want to replace it via multi-index, such as {(1, 3):'rep1', (4, 7):'rep2', (8, 9):'rep3'}, without disturbing the index order. How can I do it?

Pseudo-code (in Python 2.7):

str = 'abcdefghij'
replacement = {(1, 3):'123', (4, 7):'+', (8, 9):'&'} # right index isn't include

# after some replacements:
str = some_replace(str, replacement)
# i want to get this:
print str
# 'a123d+h&j'
martineau
  • 119,623
  • 25
  • 170
  • 301

1 Answers1

5
# since string is immutable, make a list out of the string to modify in-place
lst = list(str)

Use slice to modify items, a stronger explanation about slice and assignment can be found here; slice(*k) creates a slice object from the keys of the replacement. For instance, slice(*(1, 3)) gives a slice of slice(1, 3) which is equivalent to lst[1:3] when used as index, and replaces the corresponding elements with the corresponding value when the assignment on the slice is called:

# Here sort the index in reverse order so as to avoid tracking the index change due to the 
# difference of the sizes between the index and replacement
for k, v in sorted(replacement.items(), reverse=True):
    lst[slice(*k)] = v

''.join(lst)
# 'a123d+h&j'
Community
  • 1
  • 1
Psidom
  • 209,562
  • 33
  • 339
  • 356
  • @BoundaryImposition Thanks for the comment! – Psidom May 03 '17 at 15:40
  • Given that this is dark magic, I propose a stronger explanation on how `lst[slice(*k)] = v` effectively adjusts the rest of the replacement list. I thought I understood your answer at first glance but having played with it a little, I haven't the foggiest. Can't speak for the OP of course. – Lightness Races in Orbit May 03 '17 at 15:44
  • @Psidom Oh! Very nice work, Thank you so much! But can you briefly explain this like BoundaryImposition said :) – babaozhouy5 May 03 '17 at 15:48
  • Hmm, given that explanation, now I _definitely_ don't grok how the subsequent `k`s are/appear to be adjusted! – Lightness Races in Orbit May 03 '17 at 15:57
  • @Psidom eh.. the reason seems to be this, from high index to low inex. – babaozhouy5 May 03 '17 at 16:12
  • @BoundaryImposition The updated answer should be more clear and rigorous. – Psidom May 03 '17 at 16:12
  • @babaozhouy5 Right, I initially overlooked the fact that the replacement string length and index are not of same size. If they are not, then you probably have to go from the end to the start if you still want a good reference of the index. – Psidom May 03 '17 at 16:16
  • 1
    @Psidom Yes, sorry for my unclear question. Anyway, it's s a good solution! – babaozhouy5 May 03 '17 at 16:20
  • Hmm, are you saying you had to go in reverse to make it work? That makes sense, but now I'm really confused because your first version _did_ work. How?! Why didn't replacing items 4-7 with `'+'` throw off the target of the `'&'` substitution? – Lightness Races in Orbit May 03 '17 at 17:06
  • @BoundaryImposition In the first version, the loop through the dictionary happens to in such an order that the high index comes first, and then the low index since a dictionary in python is unordered. So it doesn't iterate in the way it looks like. – Psidom May 03 '17 at 17:12
  • 1
    @Psidom: Blimey! Okay so I was right to question it, hah. Not dark magic but pure chance. Already: if this answer makes a point of highlighting the deliberate reverse sort and reminding the OP that this erases the problem, it's perfect :) Thanks – Lightness Races in Orbit May 03 '17 at 17:23