Reputation: 15129
I need to create a two-dimensional array Class. I've done a work, but discovered that my class simply has an inner two-dim array, and to access the elements I have to write a redundant word 'table':
class Table
attr_accessor :table
def initialize(w,h)
@table = Array.new(h)
h.times do @table << Array.new(w)
end
end
x = Table.new(10,10)
x.table[5][6] = 'example'
and so on. The idea is that I want to write only x[5][6]
at once, to access elements. As far as I understand, I have to inherit the Array class, and extend it somehow to behave as an two-dim array. If I'm right - how do I do that?
Upvotes: 0
Views: 265
Reputation: 910
I think this might be what you're looking for. It uses the @table
instance variable to keep track of the internal array, but doesn't expose an accessor for it. Here's the definition:
class Table
def initialize(row_count, column_count)
@table = Array.new
row_count.times do |index|
@table[index] = Array.new(column_count)
end
end
def []=(row, column, value)
@table[row][column] = value
end
def [](row, column = nil)
if column.nil?
@table[row]
else
@table[row][column]
end
end
def inspect
@table.inspect
end
end
And here's how you might use it:
t = Table.new(2, 5)
t[0,0] = 'first'
t[1,4] = 'last'
t[0][1] = 'second'
puts t[0,0]
puts t.inspect
You might also want to take a look at Ruby's enumerable module rather than subclassing Array.
Upvotes: 1
Reputation: 9437
Is there any specific reason you would want to write your own array class? By default, you can tell array what to populate the new elements with, by providing the second argument:
>> a = Array.new(10, [])
=> [[], [], [], [], [], [], [], [], [], []]
Edit: Apparently, this way it populates the arrays with references to passed object, so once you do a[0][0] = "asd"
, every first element of contained arrays will change. Not cool.
>> a[0][0] = "asd"
=> "asd"
>> a
=> [["asd"], ["asd"], ["asd"], ["asd"], ["asd"], ["asd"], ["asd"], ["asd"], ["asd"], ["asd"]]
To have each contained array be unique, use the third syntax, and give it a block to execute each time - the result of the block will be used to populate the array:
>> b = Array.new(10) { [] }
=> [[], [], [], [], [], [], [], [], [], []]
>> b[0][0] = "asd"
=> "asd"
>> b
=> [["asd"], [], [], [], [], [], [], [], [], []]
Also, due to the way ruby arrays work, defining y axis size is not even necessary:
>> a = Array.new(5)
=> [nil, nil, nil, nil, nil]
>> a[10]
=> nil
>> a[10] = "asd"
=> "asd"
>> a
=> [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, "asd"]
The array is automatically extended when you put something in index that is larger than current size. So, just make an array containing ten empty arrays, and you have 10*n sized array ready for use.
Upvotes: 0