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)