tags:

views:

137

answers:

6

In Ruby, I have a string of identical characters -- let's say they're all exclamation points, as in !!!!. I would like to replace the characters at certain indices with '*' if the integer corresponding to that index meets some criteria.

For example, let's say I want to replace all the characters whose indices are even numbers and are greater than 3. In the string !!!!!!!! (8 characters long), that results in !!!!*!*! (indices 4 and 6 have been replaced).

What's the most compact way to do this?

+4  A: 

Here is a version that will modify an existing string in place:

str = '!!!!!!!!'
str.split('').each_with_index do |ch, index|
  str[index] = '*' if index % 2 == 0 and index > 3
end
mikej
A: 

i'm new to ruby, but i thought i would give it a go. mikej's answer is much better.

str = '!!!!!!!!'
index = 0
str.each_char { |char|
        if (3 < index) && (index % 2 == 0) then
                str[index] = '*'
        end
        index = index + 1
}

puts str

EDIT

Here is a little better solution combining some of the others (has been tested).

str = '!!!!!!!!'
str.split('').each_with_index do |char, index| 3 < index and index % 2 == 0 ? str[index] = '*' : str[index] = char end
puts str
Berek Bryan
+1  A: 

I'm new to Ruby too, but the enum_with_index function caught my eye.

2nd Update: This is what I'd meant. This code is tested.

"!!!!!!!".split('').enum_with_index.map{|c,i|(i%2==0 and i>3)?'*':c}.inject(""){|z,c|z+c}
Carl Smotricz
i get the original string returned when tested. not really sure how to use inject (i am looking into it).
Berek Bryan
No, if you get the original string then it isn't working. I don't want to waste your time. In a couple of hours I can test this and fix it up.
Carl Smotricz
Done: My best effort, corrected and tested now.
Carl Smotricz
A: 

Possibly the most compact you can get (more compact than other solutions for sure), but who knows?

s="!!!!!!!!"
4.step(s.length-1, 2) {|i| s[i]="*"}
puts s

I'd also guess it's probably the most efficient, compared to the other solutions.

JRL
+2  A: 

For those of you who, like me, are obsessed with the endless possibilities that chained enumerators give us:

str = '!!!!!!!!'
res = '!!!!*!*!'

str.replace(str.chars.with_index.inject('') { |s, (c, i)|
  next s << c unless i%2 == 0 && i > 3
  s << '*'
})

require 'test/unit'
class TestStringReplacement < Test::Unit::TestCase
  def test_that_it_replaces_chars_at_even_indices_greater_than_3_with_asterisk
    assert_equal res, str
  end
end
Jörg W Mittag
Looks cool, and probably works better than mine :)
Carl Smotricz
I love that you included a test with this example!
JohnMetta
A: 

how about regexp?

s="!!!!!!!!" 
puts s[0..3]+s[4..s.size].gsub(/!{2}/,"*!")
marocchino