(No shared state between arrays)
input = [[1,2,3,4],[11,12,13,14]]
rows = input
cols = []; rows[0].each_index {|i| cols << rows.map {|r| r[i]}}
pp cols
# [[1, 11], [2, 12], [3, 13], [4, 14]]
#### initially the object values and references are the same
cols[0][0] == rows[0][0]
#=> true
cols[0][0] === rows[0][0]
#=> true
#### but after a change....
cols[0][0] = 'gotcha'
#### they differ
cols[0][0] == rows[0][0]
#=> false
cols[0][0] === rows[0][0]
#=> false
pp cols
# [["gotcha", 11], [2, 12], [3, 13], [4, 14]]
pp rows
# [[1, 2, 3, 4], [11, 12, 13, 14]]
Encapsulate array elements so the elements don't change but only their state
class Cell
attr_accessor :value
def initialize(value)
@value = value
end
def to_s
@value.to_s
end
def inspect
to_s
end
end
#### first map the values to cell instances
input = [[1,2,3,4],[11,12,13,14]]
rows = input.map {|row| row.map {|v| Cell.new(v)}}
cols = []; rows[0].each_index {|i| cols << rows.map {|r| r[i]}}
pp cols
# [[1, 11], [2, 12], [3, 13], [4, 14]]
cols[0][0] == rows[0][0]
#=> true
cols[0][0] === rows[0][0]
#=> true
#### array elements don't change, just the cell values,
#### so references are retained across arrays
cols[0][0].value = 'new'
cols[0][0] == rows[0][0]
#=> true
cols[0][0] === rows[0][0]
#=> true
pp cols
# [["new", 11], [2, 12], [3, 13], [4, 14]]
pp rows
# [["new", 2, 3, 4], [11, 12, 13, 14]]
- Store all row and column elements in a single array
- Cell objects delegate their value to the position in the array
If you allow direct access to the column and row arrays, and to the array elements, you break encapsulation. This is true whether you delegate to an array or provide direct access. Because then you can do the following (using lucasefe's implementation):
mytable.columns #=> Bricks::Index object delegating to internal array
mytable.columns[0] #=> Array of Bricks::Cells objects
mytable.columns[0] = "oops" #=> corrupted column and rows
mytable.columns[0][0] = "mistake" #=> corrupted cell, column and row