Forum: Ruby Fetching objects used as hash keys

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Andre N. (Guest)
on 2007-02-06 21:04
(Received via mailing list)
Hello

I'm using objects which are instances of a class that has 3 instance
variables as hash keys, but I'm using the value of only two of those
instance variables for the hash calculation. It's something like this:

class A
  attr_reader :x, :y, :z

  def initialize(x, y)
    @x = x
    @y = y
    @z = rand
  end

  def hash
    @x.hash ^ @y.hash
  end

  def eql?(other)
    @x == other.x and @y == other.y
  end
end

a1 = A.new('foo', 'bar')  # say @z = 0.25 here
a2 = A.new('foo', 'bar')  # say @z = 0.90 here

h = {}
h[a1] = true
p h[a2] #=> true

I did it this way because when I need to test the presence of an object
in the hash, the value of @z is not known (and doesn't matter). However,
once I know the object is there, I'd like to fetch it, and check the
value of @z of the object that was used as the hash key, that is, I'd
like to get "0.25" in the example above.

What I had to do was use a hash of hashes instead, so I currently I have

h = {}
x = 'foo'
h[x] = {
  :y => 'bar'
  :z => rand
}

So I'm guessing maybe a hash isn't the correct data structure to do what
I want here (i.e., fetch an object based on some of its attributes).
Anyone has suggestions on how I could implement that, if possible
keeping the efficiency of a hash access?

Thanks in advance,
Andre
gga (Guest)
on 2007-02-08 04:36
(Received via mailing list)
On 6 feb, 16:04, Andre N. <removed_email_address@domain.invalid> wrote:
>     @x = x
>   end
> end
>
> a1 = A.new('foo', 'bar')  # say @z = 0.25 here
> a2 = A.new('foo', 'bar')  # say @z = 0.90 here
>
> h = {}
> h[a1] = true
> p h[a2] #=> true
>

Okay, your explanation does not make much sense.  But... if @z is not
needed and you want it to be returned as the hash value, why is it in
the class?   Make *that* the hash value, like:

h = {}
h[a1] = rand
p h[a2]
>> 0.25

should give you what you want.  If you do want it in the class, then
you don't need a hash.  Just doing a1.z should give you back what you
want.
If you need it in both, pass it around when you create it, like:

h = {}
[ a1, a2 ]. each { |key|
  z = h[key] || rand
  h[key] = z
  key.z = z              # make z attr_accessor, not attr_reader of
course
}


Or did I miss something?
Patrick H. (Guest)
on 2007-02-08 17:07
(Received via mailing list)
On 2/6/07, Andre N. <removed_email_address@domain.invalid> wrote:
> So I'm guessing maybe a hash isn't the correct data structure to do what
> I want here (i.e., fetch an object based on some of its attributes).
> Anyone has suggestions on how I could implement that, if possible
> keeping the efficiency of a hash access?

You probably want a set.

require "set"

class A
 attr_reader :x, :y, :z

 def initialize(x, y, z = rand)
   @x = x
   @y = y
   @z = z
 end

 def hash
   @x.hash ^ @y.hash
 end

 def eql?(other)
   @x == other.x and @y == other.y
 end
end

a1 = A.new('foo', 'bar')  # say @z = 0.25 here
puts "a1.z: #{a1.z}"
a2 = A.new('foo', 'bar')  # say @z = 0.90 here
puts "a2.z: #{a2.z}"

s = Set.new [a1]
p s
s.add(a2)
p s
p s.include?(a2)
p s.find { |m| m.eql?(a2) }.z

# Make it nicer:
def s.[] (lookup)
  self.find {|elem| elem.eql?(lookup) }
end

p s[a2].z

# Hope that helps
# pth
This topic is locked and can not be replied to.