Hash of hash?

hi,

I am totally new to Ruby and am trying to code a hash of a hash.
Somehow I always get a syntax error, but am unable to resolve it.

This is what I have:

File 1:
class Hashhash
   def initialize
     @dt = { 2 => {2 => "H", 3 => "C"},
             3 => {2 => "H", 9 => "Dh"},
            "T" => {2 => "C", 9 => "S"}
     }

     return @dt
  end
end

File 2:
require 'Hashhash'

ah = Hashhash.new

out = ah["T"][9]

p out

I always get this error:
test.rb:5: undefined method `[]' for #<Hashhash:0x2bd2e30>
(NoMethodError)

But when I try to code something in irb it works:
irb(main):006:0* dt = { 2 => {2 => "H", 3 => "C"}}
=> {2=>{2=>"H", 3=>"C"}}
irb(main):007:0> puts dt[2][2]
H
=> nil

What am I doing wrong??

Thanks in advance

···

--
Posted via http://www.ruby-forum.com/.

Hi Jeroen,

I think you have to explicitly define a method for your class
(and a = method, if you want to write values with this syntax too).

Flo

···

Jeroen Lodewijks <ruby-forum@wondercool.com> wrote:

class Hashhash
...
end

out = ah["T"][9]
...
test.rb:5: undefined method `' for #<Hashhash:0x2bd2e30>

First of all, what you get is not a syntax error (which would have produced an
error message like: syntax error, ....). The error you see is caused by
calling a method on an object for which it isn't defined.

The problem is that when you call the new method of a class (in your case,
Hashhash.new), you don't get the value returned by initialize, but the object
created by new. This means that ah doesn't contain a hash, but a Hashhash,
which doesn't have a method.

You have several options on how to do what you want. Depending on what exactly
you need, I think the easiest ones are:
* define an method for the Hashhash class. This way, the code you wrote
will work exactly as you meant. Defining such a method is easy. Inside the
definition of the Hashhash class, do:

  def (key)
    @dt[key]
  end

Calling this method will return the hash stored in @dt under key. Since this
is a hash, you'll be able to retrieve the value corresponding to the key 2

* define a method for the Hashhash class which returns the instance variable
@dt and use that to access the elements. To define a method which only returns
the value of an instance variable, you can use the attr_reader class method:

  class Hashhash
   
    attr_reader :dt

    def initialize
      ...
    end

  end

Then, you can write

  ha = Hashhash.new

  ha.dt[2][2]

* Do not use the Hashhash class and use a simple hash of hashes:

  ah = { 2 => {2 => "H", 3 => "C"},
    3 => {2 => "H", 9 => "Dh"},
    "T" => {2 => "C", 9 => "S"}
    }
  ah[2][2]

As for the reason it works in irb... well, from what you show us, you aren't
using the same code you used in the script. At least, in this case dt isn't an
instance variable (since it doesn't start with @).

I hope this helps

Stefano

···

On Friday 19 June 2009, Jeroen Lodewijks wrote:

>hi,
>
>I am totally new to Ruby and am trying to code a hash of a hash.
>Somehow I always get a syntax error, but am unable to resolve it.
>
>This is what I have:
>
>File 1:
>class Hashhash
> def initialize
> @dt = { 2 => {2 => "H", 3 => "C"},
> 3 => {2 => "H", 9 => "Dh"},
> "T" => {2 => "C", 9 => "S"}
> }
>
> return @dt
> end
>end
>
>File 2:
>require 'Hashhash'
>
>ah = Hashhash.new
>
>out = ah["T"][9]
>
>p out
>
>I always get this error:
>test.rb:5: undefined method `' for #<Hashhash:0x2bd2e30>
>(NoMethodError)
>
>But when I try to code something in irb it works:
>irb(main):006:0* dt = { 2 => {2 => "H", 3 => "C"}}
>=> {2=>{2=>"H", 3=>"C"}}
>irb(main):007:0> puts dt[2][2]
>H
>=> nil
>
>What am I doing wrong??
>
>Thanks in advance

Hi,

···

Am Freitag, 19. Jun 2009, 23:08:12 +0900 schrieb Jeroen Lodewijks:

class Hashhash
   def initialize
     @dt = { 2 => {2 => "H", 3 => "C"},
             3 => {2 => "H", 9 => "Dh"},
            "T" => {2 => "C", 9 => "S"}
     }
     return @dt
  end
end

  def key ; @dt[ key] ; end

You don't need to return anything from `initialize' because its
return value is discarded and the invoking `new' method always
returns the created object. Btw you don't need to return anything
rom assigment methods `member=' either.

Bertram

--
Bertram Scharpf
Stuttgart, Deutschland/Germany
http://www.bertram-scharpf.de

Thanks all for the replies, very clear.

I think I will implement an accessor to the hash, I come from a Perl
world and would build the hash in a seperate routine (to hide the
initialisation) that returns a reference to the hash.

Would it be possible to make Hashhash inherit from Hash (by using <
Hash) and be able to use the [][] operator immediately in a way?

···

--
Posted via http://www.ruby-forum.com/.

Alternatively Jeroen can simply create a Hash with a default_proc
which will recursively insert Hashes:

irb(main):001:0> ha = Hash.new {|h,k| h[k] = Hash.new(&h.default_proc)}
=> {}
irb(main):002:0> ha[1][2][3]
=> {}
irb(main):003:0> ha[1][2][3]=123
=> 123
irb(main):004:0> ha
=> {1=>{2=>{3=>123}}}
irb(main):005:0>

Kind regards

robert

···

2009/6/19 Florian Weingarten <usenet@hackvalue.de>:

Jeroen Lodewijks <ruby-forum@wondercool.com> wrote:

class Hashhash
...
end

out = ah["T"][9]
...
test.rb:5: undefined method `' for #<Hashhash:0x2bd2e30>

Hi Jeroen,

I think you have to explicitly define a method for your class
(and a = method, if you want to write values with this syntax too).

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Thanks all for the replies, very clear.

I think I will implement an accessor to the hash, I come from a Perl world and would build the hash in a seperate routine (to hide the initialisation) that returns a reference to the hash.

If you create a new class then the constructor is just sufficient - you do not need another method that hides away invocation of YourClass.new.

Would it be possible to make Hashhash inherit from Hash (by using < Hash) and be able to use the operator immediately in a way?

Actually, you do not need to create another class (see my earlier example). For that it might make sense to create a method that returns a new instance with the initialization I have shown.

If you lack explanation: the construct Hash.new {|h,k| ...} creates a new Hash instance with its default_proc set to the block you provide. This block is invoked whenever there is a key miss. In my case I just built it in a way as to create another Hash on the fly with the same default_proc and stuff it in the other Hash. The default_proc propagation ensures you can arbitrarily nest Hashes. Of course, you can also do something like this if you know you just need one level of nested Hashes

ha = Hash.new {|h,k| h[k] = {}}

Question is whether you want to bother to create a class for this. IMHO this makes only sense if you want to put additional logic into it (e.g. checking elements that are placed in the Hash).

Kind regards

  robert

···

On 19.06.2009 17:42, Jeroen Lodewijks wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/