Reputation: 3166
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
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
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
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
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
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
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
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
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
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
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