Hash == not always working? Or am I missing something?

Hi everyone,

I am having difficulty with Hash and sometimes Arrays with ==. Below
is an example with Hashes. I am trying to do some simple cleanup of
our data and was trying TDD some code but I do not understand why it
says my 2 Hashes are different. They appear identical but show up as
false using ==.

According to ri :

···

Hash#==
hsh == anOtherHash -> true or false


Equality—Two hashes are equal if they each contain the same
number of keys and if each key-value pair is equal to (according
to
Object#==) the corresponding elements in the other hash.
h1 = { “a” => 1, “c” => 2 }
h2 = { 7 => 35, “c” => 2, “a” => 1 }
h3 = { “a” => 1, “c” => 2, 7 => 35 }
h4 = { “a” => 1, “d” => 2, “f” => 35 }
h1 == h2 #=> false
h2 == h3 #=> true
h3 == h4 #=> false

This should work. The code is below along with the Test::Unit
output.

Am I missing something stupid???

module ShipToCleanUp
def notes
results = []
1.upto(6) do |i|
results << send(“note#{i}”)
end
results.join(" ").strip
end

def word_counts
results = Hash.new{|h,k| h[k] = 0}
notes.split(/\s+/).each{|word| results[word]+=1}
results
end
end

if FILE == $0
require ‘test/unit’
class ShipToCleanUpTester < Test::Unit::TestCase
class ShipTo
include ShipToCleanUp
attr_accessor :note1, :note2, :note3, :note4, :note5, :note6
def initialize(n1=’’, n2=’’, n3=’’, n4=’’, n5=’’, n6=’’)
@note1, @note2, @note3, @note4, @note5, @note6 = n1, n2, n3,
n4, n5, n6
end
end

def setup
  @shipTo1 = ShipTo.new('LINE 1 AND SOME MORE ON LINE 1 ', '      

***** LINE 2 ***** ', ‘’, ‘’, 'LINE 5 ', ‘AND LINE 6’)
end

def test_word_counts
  expected = {}
  expected['LINE'] = 5
  expected['1']  = 2
  expected['AND'] = 2
  expected['SOME'] = 1
  expected['MORE'] = 1
  expected['ON'] = 1
  expected['*****'] = 2
  expected['2']  = 1
  expected['5']  = 1
  expected['6']  = 1
        
  assert_equal(expected, @shipTo1.word_counts)
end

def test_notes_some_empty
  expected = "1     6"
  assert_equal(expected, ShipTo.new("1", '', '', '', '', 

‘6’).notes)
end

def test_notes_empty
  expected = ""
  assert_equal(expected, ShipTo.new.notes)
end

def test_notes
  expected = "LINE 1 AND SOME MORE ON LINE 1        ***** LINE 2 

***** LINE 5 AND LINE 6"
assert_equal(expected, @shipTo1.notes)
end
end
end

When I run the code I get

Loaded suite C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/rbC.tmp
Started
…F
Finished in 0.04 seconds.

  1. Failure:
    test_word_counts(ShipToCleanUpTester)
    [C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/rbC.tmp:46]:
    <{“6”=>1,
    “AND”=>2,
    “LINE”=>5,
    "=>2,
    “1”=>2,
    “2”=>1,
    “ON”=>1,
    “SOME”=>1,
    “5”=>1,
    “MORE”=>1}> expected but was
    <{“6”=>1,
    “AND”=>2,
    “LINE”=>5,
    "
    ”=>2,
    “1”=>2,
    “2”=>1,
    “ON”=>1,
    “SOME”=>1,
    “5”=>1,
    “MORE”=>1}>.

4 tests, 4 assertions, 1 failures, 0 errors

Any insight would be greatly appreciated.

Thanks,

Walt


Walter Szewelanczyk
IS Director
M.W. Sewall & CO. email : walter@mwsewall.com
259 Front St. Phone : (207) 442-7994 x 128
Bath, ME 04530 Fax : (207) 443-6284


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

[...]

      expected = {}

your 2 Hash are not the same : they don't use the same default value

Guy Decoux

I am having difficulty with Hash and sometimes Arrays with ==. Below
is an example with Hashes. I am trying to do some simple cleanup of
our data and was trying TDD some code but I do not understand why it
says my 2 Hashes are different. They appear identical but show up as
false using ==.

I see you make usage of #default_proc… but the Hash you
compare against does’t contains a equal #default_proc.

ri Hash.default_proc
------------------------------------------------------ Hash#default_proc
hsh.default_proc → anObject

···

On Fri, 16 Apr 2004 00:07:55 +0900, walte wrote:

 If +Hash::new+ was invoked with a block, return that block,
 otherwise return +nil+.

    h = Hash.new {|h,k| h[k] = k*k }   #=> {}
    p = h.default_proc                 #=> #<Proc:0x401b3d08@-:1>
    a = []                             #=> []
    p.call(a, 2)
    a                                  #=> [nil, nil, 4]


Simon Strandgaard

You compare a hash created with a block argument to a hash created
without a block argument. That’s why they are not equal. Actually it’s
complicated to compare such hashes.

You can implement a workaround like that:

$block = lambda {|h,k| h[k] = 0}
hash1 = Hash.new(&$block)
hash2 = Hash.new(&$block)

Perhaps it would be easier to just use
hash = Hash.new(0)
for your hashes.

···

On 2004-04-15 23:07:55 +0900, walter@mwsewall.com wrote:

I am having difficulty with Hash and sometimes Arrays with ==. Below
is an example with Hashes. I am trying to do some simple cleanup of
our data and was trying TDD some code but I do not understand why it
says my 2 Hashes are different. They appear identical but show up as
false using ==.


c, s, x = gets, c[0, 2].to_i, “dsfd;kfoA,.iyewrkldJKDHSUB”
puts (1…(c.size / 2)).inject(“”) do |p, i|
p << (c[2 * i, 2].to_i(16) ^ x[(s += 1) && s -1])
end

Hi,

···

In message “Hash == not always working? Or am I missing something?” on 04/04/15, walter@mwsewall.com walter@mwsewall.com writes:

I am having difficulty with Hash and sometimes Arrays with ==. Below
is an example with Hashes. I am trying to do some simple cleanup of
our data and was trying TDD some code but I do not understand why it
says my 2 Hashes are different. They appear identical but show up as
false using ==.

Because they have different default proc (the one has none, the other
have {|h,k| h[k] = 0}. The document should have mentioned about the
default value.

						matz.
results = Hash.new{|h,k| h[k] = 0}

[…]

  expected = {}

your 2 Hash are not the same : they don’t use the same default value

Guy Decoux

So even though the items are the same, that doesn’t matter if the
default value is different. Why would that be? And if so, should ri
be updated to reflect this (or have newer version already been
updated (I am using 1.8.1r11 Prag-Prog installer)?

Walt

···

Walter Szewelanczyk
IS Director
M.W. Sewall & CO. email : walter@mwsewall.com
259 Front St. Phone : (207) 442-7994 x 128
Bath, ME 04530 Fax : (207) 443-6284


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

[…]

  expected = {}

your 2 Hash are not the same : they don’t use the same default value

Guy Decoux

Thanks for the response Guy,

I changed both hashes to be created by Hash.new{|h,k| h[k] = 0} but I
still get the error…

module ShipToCleanUp def notes results = [] 1.upto(6) do |i| results << send("note#{i}") end results.join(" ").strip end

def word_counts
results = Hash.new{|h,k| h[k] = 0}
notes.split(/\s+/).each{|word| results[word]+=1}
results
end
end

if FILE == $0
require ‘test/unit’
class ShipToCleanUpTester < Test::Unit::TestCase
class ShipTo
include ShipToCleanUp
attr_accessor :note1, :note2, :note3, :note4, :note5, :note6
def initialize(n1=‘’, n2=‘’, n3=‘’, n4=‘’, n5=‘’, n6=‘’)
@note1, @note2, @note3, @note4, @note5, @note6 = n1, n2, n3,
n4, n5, n6
end
end

def setup
  @shipTo1 = ShipTo.new('LINE 1 AND SOME MORE ON LINE 1 ', '      

***** LINE 2 ***** ', ‘’, ‘’, 'LINE 5 ', ‘AND LINE 6’)
end

def test_word_counts
  expected = Hash.new{|h,k| h[k] = 0}
  expected['LINE'] = 5
  expected['1']  = 2
  expected['AND'] = 2
  expected['SOME'] = 1
  expected['MORE'] = 1
  expected['ON'] = 1
  expected['*****'] = 2
  expected['2']  = 1
  expected['5']  = 1
  expected['6']  = 1
        
  assert_equal(expected, @shipTo1.word_counts)
end

def test_notes_some_empty
  expected = "1     6"
  assert_equal(expected, ShipTo.new("1", '', '', '', '', 

‘6’).notes)
end

def test_notes_empty
  expected = ""
  assert_equal(expected, ShipTo.new.notes)
end

def test_notes
  expected = "LINE 1 AND SOME MORE ON LINE 1        ***** LINE 2 

***** LINE 5 AND LINE 6"
assert_equal(expected, @shipTo1.notes)
end
end
end

Loaded suite C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/rbC.tmp Started ...F Finished in 0.04 seconds.
  1. Failure:
    test_word_counts(ShipToCleanUpTester)
    [C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/rbC.tmp:46]:
    <{“6”=>1,
    “AND”=>2,
    “LINE”=>5,
    "=>2,
    “1”=>2,
    “2”=>1,
    “ON”=>1,
    “SOME”=>1,
    “5”=>1,
    “MORE”=>1}> expected but was
    <{“6”=>1,
    “AND”=>2,
    “LINE”=>5,
    "
    ”=>2,
    “1”=>2,
    “2”=>1,
    “ON”=>1,
    “SOME”=>1,
    “5”=>1,
    “MORE”=>1}>.

4 tests, 4 assertions, 1 failures, 0 errors

···

Walter Szewelanczyk
IS Director
M.W. Sewall & CO. email : walter@mwsewall.com
259 Front St. Phone : (207) 442-7994 x 128
Bath, ME 04530 Fax : (207) 443-6284


Try this

   class MyHash < Hash
      def default(k)
         self[k] = 0
      end
   end

module ShipToCleanUp
  def notes
    results =
    1.upto(6) do |i|
      results << send("note#{i}")
    end
    results.join(" ").strip
  end
  
  def word_counts
    results = Hash.new{|h,k| h[k] = 0}

       results = MyHash.new

    notes.split(/\s+/).each{|word| results[word]+=1}
    results
  end
end

if __FILE__ == $0
  require 'test/unit'
  class ShipToCleanUpTester < Test::Unit::TestCase
    class ShipTo
      include ShipToCleanUp
      attr_accessor :note1, :note2, :note3, :note4, :note5, :note6
      def initialize(n1='', n2='', n3='', n4='', n5='', n6='')
        @note1, @note2, @note3, @note4, @note5, @note6 = n1, n2, n3,
n4, n5, n6
      end
    end
    
    def setup
      @shipTo1 = ShipTo.new('LINE 1 AND SOME MORE ON LINE 1 ', '
***** LINE 2 ***** ', '', '', 'LINE 5 ', 'AND LINE 6')
    end

    def test_word_counts
      expected = Hash.new{|h,k| h[k] = 0}

         expected = MyHash.new

      expected['LINE'] = 5

Guy Decoux

for a fairly simple workaround, try this line instead:

assert_equal(expected.sort, @shipTo1.word_counts.sort)

it will convert the hashes to an array, sort them the same way, and
compare them.

cheers,
–Mark

···

On Apr 15, 2004, at 7:37 AM, walter@mwsewall.com wrote:

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

[…]

  expected = {}

your 2 Hash are not the same : they don’t use the same default value

Guy Decoux

Thanks for the response Guy,

I changed both hashes to be created by Hash.new{|h,k| h[k] = 0} but I
still get the error…
[…]