Coder_Nick
Coder_Nick

Reputation: 841

Make a square multiplication table in Ruby

I got this question in an interview and got almost all the way to the answer but got stuck on the last part. If I want to get the multiplication table for 5, for instance, I want to get the output to be formatted like so:

1, 2, 3, 4, 5
2, 4, 6, 8, 10
3, 6, 9, 12, 15
4, 8, 12, 16, 20
5, 10, 15, 20, 25

My answer to this is:

def make_table(n)
  s = ""
  1.upto(n).each do |i|
    1.upto(n).each do |j|
      s += (i*j).to_s
    end
    s += "\n"
  end
  p s
end

But the output for make_table(5) is:

"12345\n246810\n3691215\n48121620\n510152025\n"

I've tried variations with array but I'm getting similar output.

What am I missing or how should I think about the last part of the problem?

Upvotes: 3

Views: 1540

Answers (5)

Ray
Ray

Reputation: 241

You can make it much shorter but here's my version.

range = Array(1..12)
range.each do |element|
  range.map { |item| print "#{element * item} " } && puts
end

Upvotes: 0

Arun Kumar Mohan
Arun Kumar Mohan

Reputation: 11915

You don't need to construct a string if you're only interested in printing the table and not returning the table(as a string).

(1..n).each do |a|
  (1..n-1).each { |b| print "#{a * b}, " }
  puts a * n
end

Upvotes: 2

Eric Duminil
Eric Duminil

Reputation: 54223

You can use map and join to get a String in one line :

n = 5 
puts (1..n).map { |x| (1..n).map { |y| x * y }.join(', ') }.join("\n")

It iterates over rows (x=1, x=2, ...). For each row, it iterates over cells (y=1, y=2, ...) and calculates x*y. It joins every cells in a row with ,, and joins every rows in the table with a newline :

1, 2, 3, 4, 5
2, 4, 6, 8, 10
3, 6, 9, 12, 15
4, 8, 12, 16, 20
5, 10, 15, 20, 25

If you want to keep the commas aligned, you can use rjust :

puts (1..n).map { |x| (1..n).map { |y| (x * y).to_s.rjust(3) }.join(',') }.join("\n")

It outputs :

  1,  2,  3,  4,  5
  2,  4,  6,  8, 10
  3,  6,  9, 12, 15
  4,  8, 12, 16, 20
  5, 10, 15, 20, 25

You could even go fancy and calculate the width of n**2 before aligning commas :

n = 11
width = Math.log10(n**2).ceil + 1
puts (1..n).map { |x| (1..n).map { |y| (x * y).to_s.rjust(width) }.join(',') }.join("\n")

It outputs :

   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11
   2,   4,   6,   8,  10,  12,  14,  16,  18,  20,  22
   3,   6,   9,  12,  15,  18,  21,  24,  27,  30,  33
   4,   8,  12,  16,  20,  24,  28,  32,  36,  40,  44
   5,  10,  15,  20,  25,  30,  35,  40,  45,  50,  55
   6,  12,  18,  24,  30,  36,  42,  48,  54,  60,  66
   7,  14,  21,  28,  35,  42,  49,  56,  63,  70,  77
   8,  16,  24,  32,  40,  48,  56,  64,  72,  80,  88
   9,  18,  27,  36,  45,  54,  63,  72,  81,  90,  99
  10,  20,  30,  40,  50,  60,  70,  80,  90, 100, 110
  11,  22,  33,  44,  55,  66,  77,  88,  99, 110, 121

Upvotes: 2

Cary Swoveland
Cary Swoveland

Reputation: 110675

This is how I'd do it.

require 'matrix'

n = 5

puts Matrix.build(n) { |i,j| (i+1)*(j+1) }.to_a.map { |row| row.join(', ') }
1, 2, 3, 4, 5
2, 4, 6, 8, 10
3, 6, 9, 12, 15
4, 8, 12, 16, 20
5, 10, 15, 20, 25

See Matrix::build.

Upvotes: 1

user1934428
user1934428

Reputation: 22225

Without spaces between the figures, the result is indeed unreadable. Have a look at the % operator, which formats strings and numbers. Instead of

s += (i*j).to_s

you could write

s += '%3d' % (i*j)

If you really want to get the output formatted in the way you explained in your posting (which I don't find that much readable), you could do a

s += "#{i*j}, "

This leaves you with two extra characters at the end of the line, which you have to remove. An alternative would be to use an array. Instead of the inner loop, you would have then something like

s += 1.upto(n).to_a.map {|j| i*j}.join(', ') + "\n"

Upvotes: 2

Related Questions