hash of hash?

J

Jeroen Lodewijks

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
 
F

Florian Weingarten

Jeroen Lodewijks said:
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).

Flo
 
S

Stefano Crocco

|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

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
 
R

Robert Klemme

2009/6/19 Florian Weingarten said:
Jeroen Lodewijks said:
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).

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
 
B

Bertram Scharpf

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
 
J

Jeroen Lodewijks

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?
 
R

Robert Klemme

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,969
Messages
2,570,161
Members
46,705
Latest member
Stefkari24

Latest Threads

Top