Home > database >  Why str[i] * str[i 1], while str[i 1] is not a num, does not return an error in each loop?
Why str[i] * str[i 1], while str[i 1] is not a num, does not return an error in each loop?

Time:06-18

There is a method that accepts a string as an argument. The string will be formatted so every letter is followed by a number. The method should return an "uncompressed" version of the string where every letter is repeated multiple times given based on the number that appears directly after the letter.

def uncompress(str)
    new_str = ""
    (0 ... str.length - 1).each do |i|
        new_str  = str[i] * str[i   1].to_i
    end
    new_str
end

Result:

uncompress('a2b4c1') # 'aabbbbc'

Why this code does not return an error if str[i] is a number and str[i 1] is a letter?

CodePudding user response:

As you're doing substitution in a string, let's use #gsub and toss a block to it.

irb(main):028:0> "h5a2".gsub(/[a-zA-Z]\d /) { |x| x[0] * x[1..-1].to_i }
=> "hhhhhaa"

The regex is looking for a single character followed by a (potentially) multiple digit number. It then substitutes that with the character multiplied by the number. (Converting to an int with #to_i is critical as attempting to multiply a string by a string will not work.)

Or if you wish to modify the original string, you can use #gsub!.

irb(main):032:0> s = 'a2b4c1'
irb(main):033:0> s.gsub!(/[a-zA-Z]\d /) { |x| x[0] * x[1..-1].to_i }
=> "aabbbbc"
irb(main):034:0> s
=> "aabbbbc"

If the format is fixed to a single character followed by a single digit multiplier, then this is easily accommodated by a minor modification to the regex without any change to the block.

irb(main):040:0> s = 'a2b4c156'
irb(main):041:0> s.gsub(/[a-zA-Z0-9]\d/) { |x| x[0] * x[1..-1].to_i }
=> "aabbbbc555555"

Using your approach, it's important that we increment the indices up by two, so let's generate an array of indexes.

irb(main):032:0> str = "h5d3"
irb(main):033:0> (0 .. (str.length - 1) / 2).map { |i| i * 2 }
=> [0, 2]

Then we can loop over those:

def uncompress(str)
  new_str = ""

  (0 .. (str.length - 1) / 2).map { |i| i * 2 }.each do |i|
    new_str  = str[i] * str[i   1].to_i
  end

  new_str
end

And now:

irb(main):042:0> uncompress("a4d2b1")
=> "aaaaddb"

CodePudding user response:

In Ruby You could easily do it like I have shown below. We don't have to write code like C or other language.

Input

a="a2b4c1"

Program

p a.chars
   .slice_after(/\d /)
   .to_a
   .map{|x|x.last.to_i.times.map{x.first}.join}
   .join

Output

"aabbbbc"

CodePudding user response:

Scanning, Splitting, and Integer Coercion

Rather than trying to debug your code, I'll just offer what I consider a simpler and more idiomatic solution:

str = "a2b4c1"
str.scan(/\p{Alpha}\d/).map(&:chars).map { _1 * _2.to_i }
#=> ["aa", "bbbb", "c"]

By scanning for your letter number pattern and then splitting the matched patterns into an array of characters, you create a collection of array elements that are easy to iterate over. You can easily see the interim steps here by putting a comment character after any part of the method chain to inspect what's being returned.

Lastly, you just need to ensure that the second element of each character array is coerced from a string to an integer, as otherwise you are trying to multiply strings with other strings. For example "a" * "2" is not going to accomplish what you want, while "a" * 2 will.

  • Related