Printing a readable Matrix in Ruby
Asked Answered
H

10

11

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!

Henning answered 29/4, 2012 at 5:49 Comment(0)
T
15

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)
Tamathatamaulipas answered 29/4, 2012 at 6:15 Comment(0)
R
6

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 
Rufus answered 29/4, 2012 at 7:18 Comment(0)
F
3

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. =)

Fret answered 4/5, 2012 at 19:7 Comment(1)
I'll definitely check out SciRuby/NMatrix. I'm new to Ruby so I was hoping to use it for a grad project to learn a bit more. The fact that the standard matrix in Ruby is immutable caused me to just default back to C#. Didn't know if 3rd party libs would fly with my professor and was on a crunch. Also -- We graduated the same year at VT, very cool to see you're at UT. I was Math/CS and may be interested in lending to your project, I'll toss you a message.Henning
C
1

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]
Casebound answered 29/4, 2012 at 6:19 Comment(0)
N
1

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!

Netta answered 19/11, 2013 at 21:18 Comment(0)
I
1

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
Incontinent answered 5/7, 2015 at 22:14 Comment(0)
P
0

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.

Pachysandra answered 15/9, 2015 at 13:28 Comment(0)
R
0

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
Reynolds answered 20/1, 2018 at 22:31 Comment(0)
A
0

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
Aristophanes answered 9/3, 2021 at 16:6 Comment(0)
S
0

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

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

puts board

- - -
- - -
- - -
Suggestibility answered 11/5, 2023 at 18:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.