How to implement a hash whose key is another hash?

A

acmeman1

I understand that the key of a hash can be any object. Therefore,
I would think that the key of a hash can be another hash. If I have
the following code sequence. (I using ruby 1.8.5 (2006-08-25) [i486-
linux])


require 'pp'
test ={}
test["new"=>"girl"]= 100
test["new"=>"girl"]= 200
pp test

I am expecting the output to be

{{"new"=>"girl"}=>200}

However the output I am getting is

{{"new"=>"girl"}=>100,
{"new"=>"girl"}=>200}

Could some explain how to use hash key which is of type hash
 
P

Phrogz

I understand that the key of a hash can be any object. Therefore,
I would think that the key of a hash can be another hash. If I have
the following code sequence. (I using ruby 1.8.5 (2006-08-25) [i486-
linux])

require 'pp'
test ={}
test["new"=>"girl"]= 100
test["new"=>"girl"]= 200
pp test

I am expecting the output to be

{{"new"=>"girl"}=>200}

However the output I am getting is

{{"new"=>"girl"}=>100,
{"new"=>"girl"}=>200}

Could some explain how to use hash key which is of type hash

irb(main):001:0> h1 = {}
=> {}
irb(main):002:0> h2 = { :foo=>'bar' }
=> {:foo=>"bar"}
irb(main):003:0> h1[ h2 ] = 'hello'
=> "hello"
irb(main):004:0> h1[ h2 ] = 'world'
=> "world"
irb(main):005:0> h1
=> {{:foo=>"bar"}=>"world"}
irb(main):006:0> h1[ :a=>1 ] = 42
=> 42
irb(main):007:0> h1[ :a=>1 ] = 2000
=> 2000
irb(main):008:0> h1
=> {{:a=>1}=>2000, {:foo=>"bar"}=>"world", {:a=>1}=>42}


If it's TRULY the same hash, you get what you expected: the new value
overwrites the old.

What you did, and what you see on lines 6 and 7 above, is to create a
new hash on the fly that happens to have the same values as another
hash. To Ruby, those are treated as two different keys.
 
T

Tim Pease

I understand that the key of a hash can be any object. Therefore,
I would think that the key of a hash can be another hash. If I have
the following code sequence. (I using ruby 1.8.5 (2006-08-25) [i486-
linux])


require 'pp'
test ={}
test["new"=>"girl"]= 100
test["new"=>"girl"]= 200
pp test

I am expecting the output to be

{{"new"=>"girl"}=>200}

However the output I am getting is

{{"new"=>"girl"}=>100,
{"new"=>"girl"}=>200}

The problem is that you are not using the same key ...

k = {'new' => 'girl'}
k.hash #=> 1072992710

h = {}
h[k] = 100
h[k] = 200
p h #=> {{"new" => "girl"} => 200}

k = {'new' => 'girl'}
k.hash #=> 1072934850

h[k] = 300
p h #=> {{"new"=>"girl"}=>300, {"new"=>"girl"}=>200}


To use an object as a hash key, you need to implement a "hash" method
that returns the same value when the contents of the hash are the
same. But this gets tricky.

Blessings,
TwP
 
I

Ian Whitlock

unknown said:
Could some explain how to use hash key which is of type hash

Perhaps studying this will explain your confusion.

require 'pp'
test ={}
k1 = {"new"=>"girl"}
k2 = {"new"=>"girl"}
test[k1]= 100
test[k2]= 200
pp k1.eql?(k2)
pp test
test ={}
test[k1]= 100
test[k1]= 200
pp test

Note that each instance of "new"=>"girl"
is a different hash object. Basing the
key on a hash does not look like a good
idea in general. Consider what happens
when you extend k1.

k1 = {"new"=>"girl"}
test ={}
k1["bad"]="idea"
test[k1]= 100
k1["bad"]="idea"
test[k1]= 200
pp test

Keys should be stable objects.

Ian Whitlock
 
J

Jeremy Evans

unknown said:
I understand that the key of a hash can be any object. Therefore,
I would think that the key of a hash can be another hash. If I have
the following code sequence. (I using ruby 1.8.5 (2006-08-25) [i486-
linux])


require 'pp'
test ={}
test["new"=>"girl"]= 100
test["new"=>"girl"]= 200
pp test

I am expecting the output to be

{{"new"=>"girl"}=>200}

However the output I am getting is

{{"new"=>"girl"}=>100,
{"new"=>"girl"}=>200}

Could some explain how to use hash key which is of type hash

It's a bad idea to do what you are doing. However, if you really want
to, you could try installing CICPHash (sudo gem install cicphash). It's
designed to be a case insensitive hash, but it can easily be generalized
to consider arbitrary sets of keys as equal.

The default implementation will do what you want for this simple case:

irb(main):001:0> require 'pp'
=> true
irb(main):002:0> require 'cicphash'
=> true
irb(main):003:0> test = CICPHash.new
=> {}
irb(main):004:0> test["new"=>"girl"]= 100
=> 100
irb(main):005:0> test["new"=>"girl"]= 200
=> 200
irb(main):006:0> pp test
{{"new"=>"girl"}=>200}
=> nil

However, the default implementation won't necessarily work for hashes
with multiple keys, as the order of the keys in the hash is undefined.
You can change that by redefining the CICPHash#convert_key method.

However, as previously mentioned, you probably shouldn't use hashes as
hash keys.

Jeremy
 

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

Forum statistics

Threads
473,981
Messages
2,570,187
Members
46,731
Latest member
MarcyGipso

Latest Threads

Top