4

Here is my list:

liPos = [(2,5),(8,9),(18,22)]

The first item of each tuple is the starting position and the second is the ending position. Then I have a string like this:

s = "I hope that I will find an answer to my question!"

Now, considering my liPos list, I want to format the string by removing the chars between each starting and ending position (and including the surrounding numbers) provided in the tuples. Here is the result that I want:

"I tt I will an answer to my question!"

So basically, I want to remove the chars between 2 and 5 (including 2 and 5), then between 8,9 (including 8 and 9) and finally between 18,22 (including 18 and 22).

Any suggestion?

2
  • 1
    did you make a mistake in your desired answer? given your liPos, shouldn't it be "I tt I will an answer to my question!" ? Commented Aug 10, 2011 at 22:52
  • lol yeah, sorry I made a mistake, but I edited it :) Commented Aug 10, 2011 at 22:59

4 Answers 4

5

This assumes that liPos is already sorted, if it is not used sorted(liPos, reverse=True) in the for loop.

liPos = [(2,5),(8,9),(18,22)]
s = "I hope that I will find an answer to my question!"
for begin, end in reversed(liPos):
    s = s[:begin] + s[end+1:]

print s

Here is an alternative method that constructs a new list of slice tuples to include, and then joining the string with only those included portions.

from itertools import chain, izip_longest
# second slice index needs to be increased by one, do that when creating liPos
liPos = [(a, b+1) for a, b in liPos]
result = "".join(s[b:e] for b, e in izip_longest(*[iter(chain([0], *liPos))]*2))

To make this slightly easier to understand, here are the slices generated by izip_longest:

>>> list(izip_longest(*[iter(chain([0], *liPos))]*2))
[(0, 2), (6, 8), (10, 18), (23, None)]
Sign up to request clarification or add additional context in comments.

1 Comment

I have a large string and it fails to the print the source as I want. Though I haven't tried your second met yet.
3
liPos = [(2,5),(8,9),(18,22)]
s = "I hope that I will find an answer to my question!"

exclusions = set().union(* (set(range(t[0], t[1]+1)) for t in liPos) )
pruned = ''.join(c for i,c in enumerate(s) if i not in exclusions)

print pruned

Comments

3

Here is one, compact possibility:

"".join(s[i] for i in range(len(s)) if not any(start <= i <= end for start, end in liPos))

Comments

2

This ... is a quick stab at the problem. There may be a better way, but it's a start at least.

>>> liPos = [(2,5),(8,9),(18,22)]
>>>
>>> toRemove = [i for x, y in liPos for i in range(x, y + 1)]
>>>
>>> toRemove
[2, 3, 4, 5, 8, 9, 18, 19, 20, 21, 22]
>>>
>>> s = "I hope that I will find an answer to my question!"
>>>
>>> s2 = ''.join([c for i, c in enumerate(s) if i not in toRemove])
>>>
>>> s2
'I  tt I will an answer to my question!'

1 Comment

There are some obvious shortcomings to this approach. The first is that it will be slow for large lists of indexes to remove. That could be sped up with a different container type for toRemove. It may also use more memory than necessary, though changing the parameter passed to ''.join() from a list [] to a generator () would help with that.

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.