Home > database >  Make Pair and Add Each Pair Individually in Ruby
Make Pair and Add Each Pair Individually in Ruby

Time:04-29

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
  •  Tags:  
  • ruby
  • Related