views:

67

answers:

3

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?

A: 

Maybe this helps: http://www.ehow.com/how_2091651_create-multidimensional-array-ruby.html

Konamiman
Maybe. 'reading'
gmile
A: 

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.

Toms Mikoss
Yeah, I really wanna create a class to separate it's inner routings (i.e. methods) from the logic of the actual algorithm, on which I'm working now. Thanks for array auto-resizing! Didn't know that
gmile
+1  A: 

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.

Patrick Reagan