Home > OS >  How to decrement numbers inside a string?
How to decrement numbers inside a string?

Time:09-06

I have a string of integers that can be separated by a comma, hyphen or both. e.g.

str = '3,7-17,21'

I need to take those numbers and reduce them by 1 without losing their position in that string.

When I split, I lose commas and hyphens so their positions change.

Is there a nice way to turn my string into 2,6-16,20?

I started on the following but just ended up in a rabbit hole:

def reduce_hours(hours)
  hours
    .enum_for(:scan, /\d /)
    .map { Regexp.last_match(0) }
    .map(&:to_i)
    .map { |hour| hour - 1 }
    .then { hours }
end

hours = '3,7-17,21'

It just returns the original string. When I debug, it does match the numbers individually and reduce them by 1. It just doesn't return those changes to the original string. Am I close with that snippet?

CodePudding user response:

enum_for(:scan, ...), Regexp.last_match(0), then – you're overthinking it.

You can just use gsub to replace each numeric substring by its predecessor:

str = '3,7-17,21'

str.gsub(/\d /) { |hour| hour.to_i - 1 }
#=> "2,6-16,20"

The to_i round trip is needed, because strings can't be decremented directly.

The opposite direction is even easier: (via String#succ)

"2,6-16,20".gsub(/\d /, &:succ)
#=> "3,7-17,21"

CodePudding user response:

Try this:

def process_comma(str)
  str.split(',').map do |sub_str|
    sub_str.include?('-') ? process_hiphen(sub_str) : (sub_str.to_i - 1).to_s
  end.join(',')
end

def process_hiphen(str)
  str.split('-').map do |sub_str|
    (sub_str.to_i - 1).to_s
  end.join('-')
end


str = '3,7-17,21'
process_comma(str)    # "2,6-16,20"

CodePudding user response:

Sorry its not in ruby as such but this is how I have done it in c# Basically spliting it by groups first (the comma) then handling each group e.g single numbers or hyphenated number next.

var str = "3,7-17,21";
var numSec = str.Split(',');
var reduced = numSec.Select(r=> string.Join('-', r.Split('-').Select(n=> Int32.Parse(n) - 1 )));
var reJoined = string.Join(',', reduced);

Console.WriteLine(reJoined);

CodePudding user response:

You can go by each possible delimiter.

hours = '3,7-17,21'

def reduce_hours(hours)
  hours
    .split('-')
    .map { |comma_seperated_strings|
      comma_seperated_strings
        .split(',')
        .map(&:to_i)
        .map{|x| x-1}
        .map(&:to_s)
        .join(',')
    }
    .join('-')
end

puts reduce_hours(hours)
  •  Tags:  
  • ruby
  • Related