Tom
Tom

Reputation: 1105

How to decrement numbers inside a string

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?

Upvotes: 1

Views: 91

Answers (3)

Stefan
Stefan

Reputation: 114258

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"

Upvotes: 5

LinFelix
LinFelix

Reputation: 1072

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)

Upvotes: 0

Sachin Singh
Sachin Singh

Reputation: 1108

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"

Upvotes: 0

Related Questions