vpiTriumph
vpiTriumph

Reputation: 3166

Printing a readable Matrix in Ruby

Is there a built in way of printing a readable matrix in Ruby?

For example

require 'matrix'
m1 = Matrix[[1,2], [3,4]]
print m1

and have it show

=> 1 2
   3 4

in the REPL instead of:

=> Matrix[[1,2][3,4]]

The Ruby Docs for matrix make it look like that's what should show happen, but that's not what I'm seeing. I know that it would be trivial to write a function to do this, but if there is a 'right' way I'd rather learn!

Upvotes: 11

Views: 10858

Answers (10)

gideb
gideb

Reputation: 11

You can make it a string and print each row separately:

  def to_s
    @board.map { |row| row.join(' ') }.join("\n")
  end

puts board

- - -
- - -
- - -

Upvotes: 0

B Corluka
B Corluka

Reputation: 1

I had this problem just yet and haven't seen anyone posting it here, so I will put my solution if it helps someone. I know 2 for loops are not the best idea, but for smaller matrix it should be okay, and it prints beautifully and just how you want it, also without of use of require 'matrix' nor 'pp'

matrix = Array.new(numRows) { Array.new(numCols) { arrToTakeValuesFrom.sample } }

for i in 0..numRows-1 do
  for j in 0..numCols-1 do
    print " #{matrix[i][j]} "
  end
  puts ""
end

Upvotes: 0

Conor O'Brien
Conor O'Brien

Reputation: 1027

There is no inbuilt Ruby way of doing this. However, I have created a Module which can be included into Matrix that includes a method readable. You can find this code here, but it is also in the following code block.

require 'matrix'

module ReadableArrays
    def readable(factor: 1, method: :rjust)
        repr = to_a.map { |row|
            row.map(&:inspect)
        }

        column_widths = repr.transpose.map { |col|
            col.map(&:size).max + factor
        }

        res = ""
        repr.each { |row|
            row.each_with_index { |el, j|
                res += el.send method, column_widths[j]
            }
            res += "\n"
        }
        res.chomp
    end
end

## example usage ##
class Matrix
    include ReadableArrays
end
class Array
    include ReadableArrays
end

arr = [[1, 20, 3], [20, 3, 19], [-32, 3, 5]]
mat = Matrix[*arr]

p arr
#=> [[1, 20, 3], [20, 3, 19], [-2, 3, 5]]
p mat
#=> Matrix[[1, 20, 3], [20, 3, 19], [-2, 3, 5]]

puts arr.readable
#=>
#    1 20  3
#   20  3 19
#  -32  3  5
puts mat.readable
#=>
#    1 20  3
#   20  3 19
#  -32  3  5
puts mat.readable(method: :ljust)
#=>
# 1   20 3
# 20  3  19
# -32 3  5
puts mat.readable(method: :center)
#=>
#  1  20  3
#  20  3 19
# -32  3  5

Upvotes: 0

Justme0
Justme0

Reputation: 133

Here is my answer:

require 'matrix'

class Matrix
    def to_pretty_s
        s = ""
        i = 0
        while i < self.column_size
            s += "\n" if i != 0
            j = 0
            while j < self.row_size
                s += ' ' if j != 0
                s += self.element(i, j).to_s
                j += 1
            end
            i += 1
        end
        s
    end
end

m = Matrix[[0, 3], [3, 4]]

puts m # same as 'puts m.to_s'
# Matrix[[0, 3], [3, 4]]

puts m.to_pretty_s
# 0 3
# 3 4

p m.to_pretty_s
# "0 3\n3 4"

You could use Matrix#to_pretty_s to get a pretty string for format.

Upvotes: 0

Jiri Pisa
Jiri Pisa

Reputation: 11

This is working for me

require 'matrix'

class Matrix

  def print
    matrix = self.to_a
    field_size = matrix.flatten.collect{|i|i.to_s.size}.max
    matrix.each do |row|
      puts (row.collect{|i| ' ' * (field_size - i.to_s.size) + i.to_s}).join('  ')    
    end
  end

end

m = Matrix[[1,23,3],[123,64.5, 2],[0,0,0]]
m.print

Upvotes: 1

user1646024
user1646024

Reputation: 31

Ok, I'm a total newbie in ruby programming. I'm just making my very first incursions, but it happens I got the same problem and made this quick'n'dirty approach. Works with the standard Matrix library and will print columns formatted with same size.

class Matrix
  def to_readable
   column_counter = 0
   columns_arrays = []
   while column_counter < self.column_size
     maximum_length = 0
     self.column(column_counter).each do |column_element|# Get maximal size
       length = column_element.to_s.size
       if length > maximal_length
         maximum_length = length
       end
     end # now we've got the maximum size
     column_array = []
     self.column(column_counter).each do |column_element| # Add needed spaces to equalize each column
      element_string = column_element.to_s
      element_size = element_string.size
      space_needed = maximal_length - element_size +1
      if space_needed > 0
        space_needed.times {element_string.prepend " "}
        if column_counter == 0
          element_string.prepend "["
        else
          element_string.prepend ","
        end  
      end
      column_array << element_string
    end
    columns_arrays << column_array # Now columns contains equal size strings
    column_counter += 1
  end
  row_counter = 0
  while row_counter < self.row_size
    columns_arrays.each do |column|
      element = column[row_counter]
      print element #Each column yield the correspondant row in order
    end
    print "]\n"
    row_counter += 1
  end
 end
end

Any correction or upgrades welcome!

Upvotes: 1

Translunar
Translunar

Reputation: 3816

Disclaimer: I'm the lead developer for NMatrix.

It's trivial in NMatrix. Just do matrix.pretty_print.

The columns aren't cleanly aligned, but that'd be easy to fix and we'd love any contributions to that effect.

Incidentally, nice to see a fellow VT person on here. =)

Upvotes: 3

seph
seph

Reputation: 6076

You could convert it to an array:

m1.to_a.each {|r| puts r.inspect}

=> [1, 2]
   [3, 4]

EDIT:

Here is a "point free" version:

puts m1.to_a.map(&:inspect)

Upvotes: 15

sunnyrjuneja
sunnyrjuneja

Reputation: 6123

I couldn't get it to look like the documentation so I wrote a function for you that accomplishes the same task.

require 'matrix'

m1 = Matrix[[1,2],[3,4],[5,6]]

class Matrix
  def to_readable
    i = 0
    self.each do |number|
      print number.to_s + " "
      i+= 1
      if i == self.column_size
        print "\n"
        i = 0
      end
    end
  end
end

m1.to_readable

=> 1 2 
   3 4 
   5 6 

Upvotes: 6

Paul Simpson
Paul Simpson

Reputation: 2514

You can use the each_slice method combined with the column_size method.

m1.each_slice(m1.column_size) {|r| p r }
=> [1,2]
   [3,4]

Upvotes: 1

Related Questions