4

Given a sequence of inclusive string indexes,

str_indices = [[1,2],[7,8]],

what's the best way to exclude these from a string?

For example, given the above indices marked for exclusion and the string happydays, I'd like hpyda to be returned.

2
  • 1.8.7...thanks for all the answers, I'm running some tests Commented Apr 20, 2011 at 19:20
  • Better to use Array of Ranges to be more native. [(1..2), (7..8), (10..20)] Commented Apr 21, 2011 at 10:14

7 Answers 7

6

Using Ranges:

str_indices=[[1,2],[7,8]]
str="happydays"
str_indices.reverse.each{|a| str[Range.new(*a)]=''}
str
=> "hpyda"

If you don't want to modifty the original:

str_indices.reverse.inject(str){|s,a|(c=s.dup)[Range.new(*a)]='';c}
Sign up to request clarification or add additional context in comments.

2 Comments

How did you know that he mean ranges? :) I thoght it just a strange multidimensional array.
"inclusive" said 'Range' to me.
2

Guess this is the best way of doing it.

str_indices = str_indices.flatten.reverse
string = "happydays"
str_indices.each{|i| string[i]=""}

2 Comments

except when your indices are [[1,2],[6,8]]. This returns "hpydy" instead of "hpyd".
@AShelly: Yes, you are right. I didn't read the question well. To fix it, an additional step would be added when I flatten the array.
1
[[1,2],[7,8]].reverse.inject('happydays') { |m, (f,l)| m[f..l] = ''; m }

Comments

1

For ruby 1.9,

string = 'happydays'
[-1, *str_indices.flatten(1), 0].each_slice(2).map{|i, j| string[i+1..j-1]}.join

For ruby 1.8, write require 'enumerator' before this.

Comments

0

Just for fun :)

str_indices = [[1,2],[7,8]]
str = "happydays"
str_indices.flatten.reverse.inject(str.split("")){|a,i| a.delete_at i; a}.join
#=> hpyda

Comments

0

If you use a functional programming approach, you don't have to worry about the order of indexes

str = "happydays"
indexes_to_reject = [[1,7],[2,8]] # Not in "correct" order, but still works
all_indexes = indexes_to_reject.flatten(1)
str.each_char.reject.with_index{|char, index| all_indexes.include?(index)}.join

It also works with ranges:

str = "happydays"
ranges_to_reject = [1..2, 7..8]
str.chars.reject.with_index {|char, index| 
  ranges_to_reject.any?{|range| range.include?(index)}
}.join

Comments

0

The following does not require the ranges identified by str_indices to be non-overlapping or ordered in any way.

str_indices = [[4,6], [1,2], [11,12], [9,11]]
str = "whatchamacallit"

keeper_indices = str.size.times.to_a -
                 str_indices.reduce([]) { |a,(from,to)| a | (from..to).to_a }
  # => [0, 3, 7, 8, 13, 14]

str.chars.values_at(*keeper_indices).join
  #=> "wtmait"

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.