Home > Back-end >  Is there a way to take an array and modify each individual element in a unique way using a single li
Is there a way to take an array and modify each individual element in a unique way using a single li

Time:12-19

I'm attempting to modify a variable string in Ruby 2.4 that contains both a number and a unit of measurement. My goal is to take the following string, round the numeric portion, and capitalize the unit portion:

my_string = "123.456789 dollars"

There are all sorts of ways that I know of to complete this operation with multiple lines of code, but I'm working with a unique interface and in a unique environment where the goal is to write this using a single line of code that is as short as possible. I know that I can do something like this:

my_array =my_string.split; my_array[0].to_f.round(2).to_s   " "   my_array[1].capitalize

...but my goal is to do away with the semicolons, use less characters, and to avoid having to call the array twice.

My idea was to do something along the lines of:

my_string.split.*do_this*(self.to_f.round(2), self.capitalize).join(" ")

Is there any way to do something like this in Ruby?

I'm open to other ideas as well, but again, the goal is a single line of code that is as short as possible, and the ability to modify the 2 elements using different parameters on each.

CodePudding user response:

If there are only two elements, you could use then and string interpolation:

my_string.split.then { |f, s| "#{f.to_f.round(2)} #{s.capitalize}" }

Or perhaps one of:

my_string.split.then { |f, s| sprintf("%.2f #{s.capitalize}", f) }
my_string.split.then { |f, s| sprintf('%.2f %s', f, s.capitalize) }
my_string.split.then { |f, s| "%.2f #{s.capitalize}" % f }

Or, if there could be more than two elements, you could combine map and with_index:

my_string.split.map.with_index { |e, i| i == 0 ? e.to_f.round(2) : e.capitalize }.join(' ')

CodePudding user response:

The best solutions that I've found for use in Ruby 2.4 are:

my_string.split.instance_eval { |f, s| "#{f.to_f.round(2)} #{s.capitalize}" }

OR

my_string.split.instance_eval { |a| "#{a[0].to_f.round(2)} #{a[1].capitalize}" }

OR

my_string.split.map.with_index { |e, i| i == 0 ? e.to_f.round(2) : e.capitalize }.join(' ')

CodePudding user response:

my_string = "123.456789 dollars"
my_string.gsub(/\d \.\d |(?<= )[a-z]/) { |s|
  s =~ /\d/ ? s.to_f.round(2).to_s : s.upcase }
  #=> "123.46 Dollars"

The regular expression matches the string representation of a float or (|) a lower-case letter preceded by a space. (?<= ) is a positive lookbehind.

One could alternatively write

my_string.gsub(/\d \.\d |[a-z] /) { |s|
  s =~ /\d/ ? s.to_f.round(2).to_s : s.capitalize }
  • Related