I am a beginner in Ruby Programming Language. So, I am trying to get this output in Ruby. But I have no idea how to do this task.
When user give input like "123456789" Step 1. I want to first make a pair of like this "12 34 56 78 9" Step 2. Then add each pair's value individually like this "3 7 11 15 9" Step 3. Then make a single pair of the values like this "3711159" Repeat... last Step. Then repeat the process until I get single digit number like this "9"
Input = 123456789
Output number = 9
Make a pair (left to right) => 12 34 56 78 9
Sum the each pair individually => 3 7 11 15 9
Again make a single number => 3711159
Make a pair (left to right) => 37 11 15 9
Sum the each pair individually => 10 2 6 9
Again make a single number => 10269
Make a pair (left to right) => 10 26 9
Sum the each pair individually => 1 8 9
Again make a single number => 189
Make a pair (left to right) => 9 9
Sum the each pair individually => 18
Again make a single number => 18
Make a pair (left to right) => 9
I am using this code.
a = 123456789
a1 = a.to_s.scan(/..?/)
a2 = a1.map(&:to_i).sum
a3 = a2.to_s.scan(/..?/)
a4 = a3.map(&:to_i).sum
And it gives me this output
123456789
["12", "34", "56", "78", "9"]
[12, 34, 56, 78, 9]
189
["18", "9"]
27
Can anyone help me? Thanks in Advance
CodePudding user response:
You're summing the elements from [12, 34, 56, 78, 9]
:
[12, 34, 56, 78, 9].sum #=> 189
which is 12 34 56 78 9
.
Instead, you want to sum each element's digits:
[12, 34, 56, 78, 9].map { |i| i.digits.sum }
#=> [3, 7, 11, 15, 9]
Which is [1 2, 3 4, 5 6, 7 8, 9]
Applied to your code:
number = 123456789
number.to_s #=> "123456789"
.scan(/..?/) #=> ["12", "34", "56", "78", "9"]
.map(&:to_i) #=> [12, 34, 56, 78, 9]
.map { |i| i.digits.sum } #=> [3, 7, 11, 15, 9]
.join #=> "3711159"
.to_i #=> 3711159
Instead of scan
you could also use Integer#digits
which returns them as integers right away: (in reverse order though)
number = 123456789
number.digits #=> [9, 8, 7, 6, 5, 4, 3, 2, 1]
.reverse #=> [1, 2, 3, 4, 5, 6, 7, 8, 9]
.each_slice(2) #=> [[1, 2], [3, 4], [5, 6], [7, 8], [9]]
.map(&:sum) #=> [3, 7, 11, 15, 9]
.join #=> "3711159"
.to_i #=> 3711159
As a loop:
number = 123456789
while number.digits.size > 1
number = number.digits.reverse.each_slice(2).map(&:sum).join.to_i
end
number #=> 9
CodePudding user response:
You could do that as follows.
n = 123456789
s = n.to_s
#=> "123456789"
loop do
e = s.each_char.each_slice(2)
m = e.first.join.to_i
break m if m <= 9
s = e.map { |e| e.map(&:to_i).sum}.join
end
#=> 9
We can add some puts
statements to help explain the calculations being made.
puts "s = #{s}"
loop do
e = s.each_char.each_slice(2)
puts "\ne = #{e}"
puts "e.to_a = #{e.to_a}"
f = e.first
m = f.join.to_i
puts "f = #{f}, m = #{m}"
puts "Finished! Returning #{m}" if m <= 9
break m if m <= 9
s = e.map { |e| e.map(&:to_i).sum}.join
puts "s = #{s}"
end
#=> 9
s = 123456789
e = #<Enumerator:0x00007ff9333befc8>
e.to_a = [["1", "2"], ["3", "4"], ["5", "6"], ["7", "8"], ["9"]]
f = ["1", "2"], m = 12
s = 3711159
e = #<Enumerator:0x00007ff9333b6580>
e.to_a = [["3", "7"], ["1", "1"], ["1", "5"], ["9"]]
f = ["3", "7"], m = 37
s = 10269
e = #<Enumerator:0x00007ff9333ad390>
e.to_a = [["1", "0"], ["2", "6"], ["9"]]
f = ["1", "0"], m = 10
s = 189
e = #<Enumerator:0x00007ff93339fdf8>
e.to_a = [["1", "8"], ["9"]]
f = ["1", "8"], m = 18
s = 99
e = #<Enumerator:0x00007ff9368c7300>
e.to_a = [["9", "9"]]
f = ["9", "9"], m = 99
s = 18
e = #<Enumerator:0x00007ff9368bd1e8>
e.to_a = [["1", "8"]]
f = ["1", "8"], m = 18
s = 9
e = #<Enumerator:0x00007ff933394458>
e.to_a = [["9"]]
f = ["9"], m = 9
Finished! Returning 9
Note that for the enumerator e
, e.to_a
returns an array of the objects that will be generated by the enumerator.
See Enumerable#each_slice. A small point: I have used String#each_char rather than String#chars in order to produce an enumerator rather than a temporary array of letters.
One could alternatively write
loop do
e = s.scan(/..?/)
m = e.first.to_i
break m if m <= 9
s = e.map { |e| e.to_i.digits.sum}.join
end
CodePudding user response:
Two of the most important things in solving a programming problem are:
- Picking the right data structure and
- Picking the right algorithm.
In this particular case, the data structure is not very interesting, but the algorithm very much is. It is well known that the sum of the decimal digits of a natural number is the same as the remainder of that number when dividing by 9. And it is not very hard to prove that this property also holds no matter how you group, slice, and re-combine the digits.
So, we can drastically simplify the program by changing the algorithm to be just:
def iterative_sum_of_digits(n)
raise ArgumentError, 'Argument must be nonnegative' if n.negative?
return 0 if n.zero?
(n % 9).nonzero? || 9
end