3
\$\begingroup\$

Write a function that given a max argument will print a nicely aligned multiplication tables, for example, if max = 8

  1   2   3   4   5   6   7   8
  2   4   6   8  10  12  14  16
  3   6   9  12  15  18  21  24
  4   8  12  16  20  24  28  32
  5  10  15  20  25  30  35  40
  6  12  18  24  30  36  42  48
  7  14  21  28  35  42  49  56
  8  16  24  32  40  48  56  64

The code is pretty straightforward, but I am interested in any possible improvement.

def print_multiplication_table(max)
  pad = (1 + (max*max).to_s.length)
  puts (1..max)
    .to_a
    .product((1..max).to_a)
    .map{|a, b| a * b}
    .each_slice(max)
    .map{ |x| x.map(&:to_s).map{ |x| " " * (pad - x.length) + x}.join(' ')}
    .join("\n")
end

print_multiplication_table(8)
\$\endgroup\$

2 Answers 2

2
\$\begingroup\$
def print_multiplication_table(max)

I think size would be a better name for the argument. max sounds like it's the largest number in the table.

pad = (1 + (max*max).to_s.length)

Rename to column_width. Padding is the spaces that need to be added to reach the column width.

The parentheses aren't needed.

.map{ |x| x.map(&:to_s).map{ |x| " " * (pad - x.length) + x}.join(' ')}

join(' ') adds an extra space between columns. The 1 + in the calculation of the column width already gurantees there's at least one space between two numbers, so now there are at least two spaces between numbers.

If this is intended, change the 1 to 2 in the calculation of the column width, so the minimum number of spaces is determined in a single place in the code.


Since you only want to print the table, it is unnecessary to build all those temporary arrays and strings. A nested loop will be shorter and much easier to read than a chain of calls:

def print_multiplication_table(size)
  column_width = 2 + (size*size).to_s.length
  (1..size).each do |i|
    (1..size).each do |j|
      result = (i * j).to_s
      padding = " " * (column_width - result.length)
      print padding + result
    end
    print("\n")
  end
end
\$\endgroup\$
1
  • \$\begingroup\$ The original reads better -- and is more idiomatic ruby -- than the nested loop version. The temporary arrays are there for readability and because the performance hit doesn't matter. The other comments are good, though. \$\endgroup\$
    – Jonah
    Nov 30, 2015 at 0:17
4
\$\begingroup\$

Spike gave a nice answer already. I just wanted to point out one thing: This is a good use case for rjust, aka "right-justify". With that, you can skip the string-multiplication when you pad the numbers.

def print_multiplication_table(max)
  padding = (max * max).to_s.length + 1
  sequence = (1..max).to_a
  puts sequence.product(sequence)
    .map { |a, b| (a * b).to_s.rjust(padding) }
    .each_slice(max)
    .map(&:join)
    .join("\n")
end

This one only uses 1 space between columns, but 2 spaces can be had by replacing .map(&:join) with .map { |row| row.join(" ") }.

\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.