3

I have a string, and I have a list of positions of the substrings that I need to delete:

text = 'ab cd ef gh'
positions = [[2, 5], [8, 11]]

Every element of the list contains start and end position of substring. End position is exclusive, and start position is inclusive. So the string should be transformed to:

text = 'ab ef'

Length of the list with positions is unknown, so the soultion can't be just hardcoded.

Is there any effective way to delete multiple substrings by their positions? Positions can't overlap.

5
  • What are these values [2,5]? Commented Apr 6, 2017 at 9:36
  • @AKS indeces [start, end]. Judging by desired output it's [inclusive, exclusive]. Commented Apr 6, 2017 at 9:37
  • Is end index inclusive or exclusive? You have asked a very unclear question and that too without showing what you have already tried to achieve the expected output. Commented Apr 6, 2017 at 9:39
  • You can specify the spacing you need using slicing Commented Apr 6, 2017 at 9:40
  • Is it possible for positions to overlap? Commented Apr 6, 2017 at 9:52

3 Answers 3

6

Strings are immutable, so in-place deletion is a no-go. And successive concatenation is suboptimal.

You can convert the string to list so it can be mutated and simply wipe off the desired positions by deleting each unwanted slice. Use str.join to recreate your string:

text = 'ab cd ef gh'

lst = list(text)
for i in positions[::-1]: # iterate from behind so index does not shrink inwards
    del lst[slice(*i)]

text = ''.join(lst)
print(text)
# 'ab ef'

Note that conversion to list for the mutation of immutable types is also suggested by the docs as best practice:

Concatenating immutable sequences always results in a new object. This means that building up a sequence by repeated concatenation will have a quadratic runtime cost in the total sequence length. To get a linear runtime cost, you must switch to one of the alternatives below:

  1. if concatenating str objects, you can build a list and use str.join() at the end or else write to an io.StringIO instance and retrieve its value when complete
Sign up to request clarification or add additional context in comments.

Comments

4

You have to offset for future indexes. So we first get the rest of the string (excluding the two indexes) via text[:2] + text[5:] and then we also need to offset it too, because we are removing items from the string. So, we'll add our offset to each position item.

text = 'ab cd ef gh'
positions = [[2,5],[8,11]]
offsetNextIndexes = 0
for position in positions:
    text = text[:position[0] + offsetNextIndexes] + text[position[1] + offsetNextIndexes:]
    offsetNextIndexes += position[0] - position[1]
print(text)

Comments

1

This should work easily.

" ".join(text.split()[0::2])

The slicing will help here to skip some parts, it works as

[start:end:difference]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.