Given a string of digits, I am trying to insert '-' between odd numbers and '*' between even numbers. The solution below:
def DashInsertII(num)
num = num.chars.map(&:to_i)
groups = num.slice_when {|x,y| x.odd? && y.even? || x.even? && y.odd?}.to_a
puts groups.to_s
groups.map! do |array|
if array[0].odd?
array.join(" ").gsub(" ", "-")
else
array.join(" ").gsub(" ", "*")
end
end
d = %w{- *}
puts groups.join.chars.to_s
groups = groups.join.chars
# Have to account for 0 because Coderbyte thinks 0 is neither even nor odd, which is false.
groups.each_with_index do |char,index|
if d.include? char
if (groups[index-1] == "0" || groups[index+1] == "0")
groups.delete_at(index)
end
end
end
groups.join
end
is very convoluted, and I was wondering if I could do something like this:
"99946".gsub(/[13579][13579]/) {|s,x| s+"-"+x}
where s is the first odd, x the second. Usually when I substitute, I replace the matched term, but here I want to keep the matched term and insert a character between the pattern. This would make this problem much simpler.
This will work for you:
"99946".gsub(/[13579]+/) {|s| s.split("").join("-") }
# => "9-9-946"
It's roughly similar to what you tried. It captures multiple consecutive odd digits, and uses the gsub block to split and then join them separated by the "-".
This will include both solutions working together:
"99946".gsub(/[13579]+/) {|s| s.split("").join("-") }.gsub(/[02468]+/) {|s| s.split("").join("*") }
# => "9-9-94*6"
The accepted answer illustrates well the logic required to solve the problem. However, I'd like to suggest that in production code that it be simplified somewhat so that it is easier to read and understand.
In particular, we are doing the same thing twice with different arguments, so it would be helpful to the reader to make that obvious, by writing a method or lambda that both uses call. For example:
do_pair = ->(string, regex, delimiter) do
string.gsub(regex) { |s| s.chars.join(delimiter) }
end
Then, one can call it like this:
do_pair.(do_pair.('999434432', /[13579]+/, '-'), /['02468']+/, '*')
This could be simplified even further:
do_pair = ->(string, odd_or_even) do
regex = (odd_or_even == :odd) ? /[13579]+/ : /['02468']+/
delimiter = (odd_or_even == :odd) ? '-' : '*'
string.gsub(regex) { |s| s.chars.join(delimiter) }
end
One advantage to this approach is that it makes obvious both the fact that we are processing two cases, odd and even, and the values we are using for those two cases. It can then be called like this:
do_pair.(do_pair.('999434432', :odd), :even)
This could also be done in a method, of course, and that would be fine. The reason I suggested a lambda is that it's pretty minimal logic and it is used in only one (albeit compound) expression in a single method.
This is admittedly more verbose, but breaks down the logic for the reader into more easily digestible chunks, reducing the cognitive cost of understanding it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With