Hash return is not correct

class Router
  attr_accessor :make, :model
  def initialize(make, model)
   @make = make
   @model = model
  end

  def ==(other)
    return false unless other.is_a?(Router)
     make == other.make && model == other.model
  end

end

frequency = Hash.new(0)
models = %w(2000 3000 2000 3200)
models.each{|m| frequency[Router.new('Linksys',m)] += 1}
puts frequency[Car.new('Linksys','2000')]

puts should be '2' but I am getting 'zero'

···

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

No the output is correct. Your mistake is assuming that Router.new will
return the same object for the same input parameters. For example:

frequency = Hash.new(0)
models = %w(2000 3000 2000 3200)
models.each{|m| frequency[Router.new('Linksys',m)] += 1}

p frequency => {

#<Router:0x10f80ae70 @model="3000", @make="Linksys">=>1,

#<Router:0x10f80ae20 @model="2000", @make="Linksys">=>1,

#<Router:0x10f80aec0 @model="2000", @make="Linksys">=>1,

#<Router:0x10f80add0 @model="3200", @make="Linksys">=>1

}

Note each entry is a different object. This is the normal and
correct behaviour. When you do:

puts frequency[Router.new('Linksys','2000')]

I assume you meant this and not Car.new it creates yet another object which
of course is not in the hash and so returns 0.

Ruby Mania wrote in post #1107907:

  def ==(other)
    return false unless other.is_a?(Router)
     make == other.make && model == other.model

That should be eql?, and @make/@model:

  def eql?(other)
    return false unless other.is_a?(Router)
    @make.eql?(other.make) && @model.eql?(other.model)
  end

  end

You also need to override the hash method, e.g.:

  def hash()
    @make.hash ^ @model.hash
  end

end

frequency = Hash.new(0)
models = %w(2000 3000 2000 3200)
models.each{|m| frequency[Router.new('Linksys',m)] += 1}
puts frequency[Car.new('Linksys','2000')]

As noted, should be Router:

  puts frequency[Router.new('Linksys','2000')]

···

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

Maybe the example in the Hash docs could be useful to the OP:

Quoting:
"
Hash Keys
Two objects refer to the same hash key when their hash value is
identical and the two objects are eql? to each other.
A user-defined class may be used as a hash key if the hash and eql?
methods are overridden to provide meaningful behavior. By default,
separate instances refer to separate hash keys.
A typical implementation of hash is based on the object’s data while
eql? is usually aliased to the overridden == method:
(...)
"

I hope this helps.

e.

···

On Mon, May 6, 2013 at 9:19 AM, Peter Hickman <peterhickman386@googlemail.com> wrote:

No the output is correct. Your mistake is assuming that Router.new will
return the same object for the same input parameters. For example:

frequency = Hash.new(0)
models = %w(2000 3000 2000 3200)
models.each{|m| frequency[Router.new('Linksys',m)] += 1}

p frequency => {

#<Router:0x10f80ae70 @model="3000", @make="Linksys">=>1,

#<Router:0x10f80ae20 @model="2000", @make="Linksys">=>1,

#<Router:0x10f80aec0 @model="2000", @make="Linksys">=>1,

#<Router:0x10f80add0 @model="3200", @make="Linksys">=>1

}

Note each entry is a different object. This is the normal and correct
behaviour. When you do:

puts frequency[Router.new('Linksys','2000')]

I assume you meant this and not Car.new it creates yet another object which
of course is not in the hash and so returns 0.

All,

Thanks a lot !

Damm I forgot the simple concept of contract between eql and hashcode :smiley:

Again thanks !!

Per-erik Martin wrote in post #1107918:

···

Ruby Mania wrote in post #1107907:

  def ==(other)
    return false unless other.is_a?(Router)
     make == other.make && model == other.model

That should be eql?, and @make/@model:

  def eql?(other)
    return false unless other.is_a?(Router)
    @make.eql?(other.make) && @model.eql?(other.model)
  end

  end

You also need to override the hash method, e.g.:

  def hash()
    @make.hash ^ @model.hash
  end

end

frequency = Hash.new(0)
models = %w(2000 3000 2000 3200)
models.each{|m| frequency[Router.new('Linksys',m)] += 1}
puts frequency[Car.new('Linksys','2000')]

As noted, should be Router:

  puts frequency[Router.new('Linksys','2000')]

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

I blogged about this a long time ago - in case you need a page for your
bookmarks :slight_smile:
http://blog.rubybestpractices.com/posts/rklemme/018-Complete_Class.html

Cheers

robert

···

On Mon, May 6, 2013 at 7:22 PM, Ruby Mania <lists@ruby-forum.com> wrote:

Damm I forgot the simple concept of contract between eql and hashcode :smiley:

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

**REALLY** great blog post! Information like this is rather invaluable.

···

On Mon, May 6, 2013 at 4:14 PM, Robert Klemme <shortcutter@googlemail.com> wrote:

I blogged about this a long time ago - in case you need a page for your
bookmarks :slight_smile:
http://blog.rubybestpractices.com/posts/rklemme/018-Complete_Class.html

Thanks for that Robert. BTW s/robuts/robust/.

Graham

···

On 07/05/2013 07:14, Robert Klemme wrote:

On Mon, May 6, 2013 at 7:22 PM, Ruby Mania <lists@ruby-forum.com > <mailto:lists@ruby-forum.com>> wrote:

    Damm I forgot the simple concept of contract between eql and
    hashcode :smiley:

I blogged about this a long time ago - in case you need a page for
your bookmarks :slight_smile:
http://blog.rubybestpractices.com/posts/rklemme/018-Complete_Class.html

Robert Klemme wrote in post #1108013:

···

On Mon, May 6, 2013 at 7:22 PM, Ruby Mania <lists@ruby-forum.com> wrote:

Damm I forgot the simple concept of contract between eql and hashcode :smiley:

I blogged about this a long time ago - in case you need a page for your
bookmarks :slight_smile:
http://blog.rubybestpractices.com/posts/rklemme/018-Complete_Class.html

Excellent this one is.

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