1

I followed these instructions to create a custom class for two dimensional arrays.

class SparseArray
  attr_reader :hash

  def initialize
    @hash = {}
  end

  def [](key)
    hash[key] ||= {}
  end

  def rows
    hash.length   
  end

  alias_method :length, :rows
end

How can I modify this class so I can iterate through the first and second level of an object using Object#each do? Please explain in simple terms, I'm a newbie.

Example of how I would use the each method on an object:

sparse_array[0][0] = "row 1 column 1"
sparse_array[0][1] = "row 1 column 2"
sparse_array[1][0] = "row 2 column 1"

sparse_array.each do |row|
  # sparse_array[0] on first iteration
  row.each do |column|
    # sparse_array[0][0] on first iteration
  end
end
Community
  • 1
  • 1
migu
  • 3,990
  • 5
  • 33
  • 50

2 Answers2

1

You should define each method on your SparseArray and use it to wrap values of the wrapped hash:

def each &block
  @hash.values.each(&block)
end
Mladen Jablanović
  • 41,202
  • 10
  • 87
  • 110
  • Works like a charm, thanks. Is there a way to return "" or " " for values that have no entry (e.g. if sparse_array[0][1] has no value assigned)? – migu Oct 15 '12 at 17:25
  • Not sure if I understand you. First, `each` will not traverse values with no entry. Second, `each` does not return values at all. – Mladen Jablanović Oct 15 '12 at 17:27
  • True, thx for clarifying. Another question, how can I change it to be used as `sparse_array.each_with_index do |value, index|`? Thx – migu Oct 15 '12 at 18:43
1

Hash has an each method as well:

hash.each {|key, value| puts "#{key} #{value}" }

But if you want a nicer method, put this in your class:

def each(&block)
  hash.each do |row,column_hash|
    column_hash.each do |column, value|
      block.call(row,column,value)
    end
  end
end

Then you can do things like this:

sparse_array.each do |row, column, value|
  puts "row: #{row}, column: #{column}, value: #{value}"
end
Zach Kemp
  • 11,130
  • 1
  • 27
  • 42