Hash, ==, key-value comparison

Ok,

ALthough the docs don’t mention it, Hash comparison using == checks
not only the key value pairs, but also the default value / default
procs.

So how does one compare 2 hashes key-value pairs. I can see that it
might be useful to distinguish between 2 hashes whose key-value pairs
are the same but the default value/default proc are different, but I
would think that would be much less often than wanting to know if the
key-value pairs are the same.

Maybe I am thinking about this all wrong, but I always viewed a Hash
as a Hash, and yes some might have a default value and some might
have a default proc, but it is the data (the key-value pairs) that,
to me, make up the Hash. The default data/procs are convenience that
make it easier to work with a Hash, but I would think that {} and
Hash.new(3) would be == if their key-value pairs would be equal.

Assuming that I am in the minority here about ==, what is the proper
way to see if 2 Hashes key-value pairs are the same.

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


I can contribute a patch to:

  • Change ‘==’ method to compare only key-value pairs.
  • Add Hash#=== method to act like current Hash#==

Comments?

Regards,

···

On Fri, Apr 16, 2004 at 02:04:10AM +0900, walter@mwsewall.com wrote:

Ok,

ALthough the docs don’t mention it, Hash comparison using == checks
not only the key value pairs, but also the default value / default
procs.

So how does one compare 2 hashes key-value pairs. I can see that it


University of Athens I bet the human brain
Physics Department is a kludge --Marvin Minsky

how about

(a.keys - b.keys).empty? and (a.values - b.values).empty?

-a

···

On Fri, 16 Apr 2004 walter@mwsewall.com wrote:

Ok,

ALthough the docs don’t mention it, Hash comparison using == checks
not only the key value pairs, but also the default value / default
procs.

So how does one compare 2 hashes key-value pairs. I can see that it
might be useful to distinguish between 2 hashes whose key-value pairs
are the same but the default value/default proc are different, but I
would think that would be much less often than wanting to know if the
key-value pairs are the same.

Maybe I am thinking about this all wrong, but I always viewed a Hash
as a Hash, and yes some might have a default value and some might
have a default proc, but it is the data (the key-value pairs) that,
to me, make up the Hash. The default data/procs are convenience that
make it easier to work with a Hash, but I would think that {} and
Hash.new(3) would be == if their key-value pairs would be equal.

Assuming that I am in the minority here about ==, what is the proper
way to see if 2 Hashes key-value pairs are the same.

EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328
URL :: Solar-Terrestrial Physics Data | NCEI
TRY :: for l in ruby perl;do $l -e “print "\x3a\x2d\x29\x0a"”;done
===============================================================================

Ok,

ALthough the docs don’t mention it, Hash comparison using == checks
not only the key value pairs, but also the default value / default
procs.

So how does one compare 2 hashes key-value pairs. I can see that it
might be useful to distinguish between 2 hashes whose key-value pairs
are the same but the default value/default proc are different, but I
would think that would be much less often than wanting to know if the
key-value pairs are the same.

I posted this in another thread, but I figured I should dup it here:

for two hashes a and b:

a.sort = b.sort

It converts them to arrays, and sorts them. This should do it.

Maybe I am thinking about this all wrong, but I always viewed a Hash
as a Hash, and yes some might have a default value and some might
have a default proc, but it is the data (the key-value pairs) that,
to me, make up the Hash. The default data/procs are convenience that
make it easier to work with a Hash, but I would think that {} and
Hash.new(3) would be == if their key-value pairs would be equal.

I agree that the way == works with hashes seems strange; I would expect
it to just compare keys/values. OTOH, I can see how some might feel
default values are an important part of determining equality.

cheers,
–Mark

···

On Apr 15, 2004, at 10:04 AM, walter@mwsewall.com wrote:

walter@mwsewall.com wrote:

This will work:

irb(main):001:0> class Hash
irb(main):002:1> def equal_content?(other)
irb(main):003:2> {}.update(self) == {}.update(other)
irb(main):004:2> end
irb(main):005:1> end
=> nil
irb(main):006:0> hash_a = Hash.new { |h, k| h[k] = rand }
=> {}
irb(main):007:0> hash_a[:foo] = “bar”
=> "bar"
irb(main):008:0> hash_a[:qux] = “quz”
=> "quz"
irb(main):009:0> hash_b = {:foo => “bar”, :qux => “quz”}
=> {:foo=>“bar”, :qux=>“quz”}
irb(main):010:0> hash_a.equal_content?(hash_b)
=> true
irb(main):011:0> {}.equal_content?(:x => 1)
=> false

Regards,
Florian Gross

Ok, > > ALthough the docs don’t mention it, Hash comparison using ==
checks > not only the key value pairs, but also the default value /
default > procs. > > So how does one compare 2 hashes key-value pairs.
I can see that it

I can contribute a patch to:

  • Change ‘==’ method to compare only key-value pairs.
  • Add Hash#=== method to act like current Hash#==

Comments?

Personally, I like the idea. You get my vote!

Regards,

University of Athens I bet the human brain
Physics Department is a kludge --Marvin Minsky

Thanks,

Walt

···

On Fri, Apr 16, 2004 at 02:04:10AM +0900, walter@mwsewall.com wrote: >


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


> > > > Assuming that I am in the minority here about ==, what is the proper > > way to see if 2 Hashes key-value pairs are the same. > > how about > > (a.keys - b.keys).empty? and (a.values - b.values).empty? >

Thanks, but that doesn’t work

a = {‘A’=>1, ‘B’=>2, ‘C’=>3}
b = {‘A’=>3, ‘B’=>2, ‘C’=>1}
puts (a.keys - b.keys).empty? and (a.values - b.values).empty?

here the keys and values are the same but belong to different
elements.

I know ways to do it, but it seems ugly and overcomplicated. Also
since it is pure ruby it is much
c = Hash.new{|h,k| h[k]=0}
c[‘A’] = 1
c[‘B’] = 2
c[‘C’] = 3

puts (a.size == b.size) && !(a.keys.collect{|k| a[k] ==
b[k]}.include?(false))
puts (a.size == c.size) && !(a.keys.collect{|k| a[k] ==
c[k]}.include?(false))

I am sure I can get a much faster ruby version, but not as nice as a
== b.

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


Hi,

At Fri, 16 Apr 2004 02:21:58 +0900,
Elias Athanasopoulos wrote in [ruby-talk:97279]:

  • Change ‘==’ method to compare only key-value pairs.
  • Add Hash#=== method to act like current Hash#==

I feel Hash#=== would test membership, i.e., alias for
Hash#key?.

···


Nobu Nakada

Hi,

···

In message “Re: Hash, ==, key-value comparison” on 04/04/16, Elias Athanasopoulos elathan@phys.uoa.gr writes:

  • Change ‘==’ method to compare only key-value pairs.
  • Add Hash#=== method to act like current Hash#==

They are possible options, along with

  • add new method (e.g. content_equal?) for membership equality.

I’m not sure which one is the best way to go.

						matz.

“Ara.T.Howard” ahoward@fattire.ngdc.noaa.gov schrieb im Newsbeitrag
news:Pine.LNX.4.44.0404151150190.12271-100000@fattire.ngdc.noaa.gov

Ok,

ALthough the docs don’t mention it, Hash comparison using == checks
not only the key value pairs, but also the default value / default
procs.

So how does one compare 2 hashes key-value pairs. I can see that it
might be useful to distinguish between 2 hashes whose key-value pairs
are the same but the default value/default proc are different, but I
would think that would be much less often than wanting to know if the
key-value pairs are the same.

Maybe I am thinking about this all wrong, but I always viewed a Hash
as a Hash, and yes some might have a default value and some might
have a default proc, but it is the data (the key-value pairs) that,
to me, make up the Hash. The default data/procs are convenience that
make it easier to work with a Hash, but I would think that {} and
Hash.new(3) would be == if their key-value pairs would be equal.

Assuming that I am in the minority here about ==, what is the proper
way to see if 2 Hashes key-value pairs are the same.

how about

(a.keys - b.keys).empty? and (a.values - b.values).empty?

Does not ensure that key value mappings are identical:

irb(main):006:0> a={1=>1,2=>2}
=> {1=>1, 2=>2}
irb(main):007:0> b={1=>2,2=>1}
=> {1=>2, 2=>1}
irb(main):008:0> (a.keys - b.keys).empty? and (a.values - b.values).empty?
=> true
irb(main):009:0> a == b
=> false

In this case == is more correct than you suggested comparison.

robert
···

On Fri, 16 Apr 2004 walter@mwsewall.com wrote:

“Florian Gross” flgr@ccan.de schrieb im Newsbeitrag
news:c5mvnb$3ktu5$1@ID-7468.news.uni-berlin.de

This will work:

… and burn a lot of mem if both hashes are huge.

Regards

robert
···

walter@mwsewall.com wrote:

irb(main):001:0> class Hash
irb(main):002:1> def equal_content?(other)
irb(main):003:2> {}.update(self) == {}.update(other)
irb(main):004:2> end
irb(main):005:1> end
=> nil
irb(main):006:0> hash_a = Hash.new { |h, k| h[k] = rand }
=> {}
irb(main):007:0> hash_a[:foo] = “bar”
=> “bar”
irb(main):008:0> hash_a[:qux] = “quz”
=> “quz”
irb(main):009:0> hash_b = {:foo => “bar”, :qux => “quz”}
=> {:foo=>“bar”, :qux=>“quz”}
irb(main):010:0> hash_a.equal_content?(hash_b)
=> true
irb(main):011:0> {}.equal_content?(:x => 1)
=> false

Regards,
Florian Gross

I will add a ChangeLog entry if it is accepted.

elathan@velka:~/hacking/ruby> cat …/test.rb
h1 = { “a” => 1, “b” => 2}

h2 = Hash.new(2)
h2[“a”] = 1
h2[“b”] = 2

puts h1 == h2
puts h1 === h2
elathan@velka:~/hacking/ruby> ./ruby …/test.rb
true
false

Enjoy,

···

On Fri, Apr 16, 2004 at 02:30:02AM +0900, walter@mwsewall.com wrote:

On Fri, Apr 16, 2004 at 02:04:10AM +0900, walter@mwsewall.com wrote: >
Ok, > > ALthough the docs don’t mention it, Hash comparison using ==
checks > not only the key value pairs, but also the default value /
default > procs. > > So how does one compare 2 hashes key-value pairs.
I can see that it

I can contribute a patch to:

  • Change ‘==’ method to compare only key-value pairs.
  • Add Hash#=== method to act like current Hash#==

Comments?

Personally, I like the idea. You get my vote!


University of Athens I bet the human brain
Physics Department is a kludge --Marvin Minsky

— /home/elathan/hacking/ruby/hash.c.orig 2004-04-15 04:46:29.000000000 +0300
+++ /home/elathan/hacking/ruby/hash.c 2004-04-15 04:52:39.000000000 +0300
@@ -1425,6 +1425,48 @@
}
if (RHASH(hash1)->tbl->num_entries != RHASH(hash2)->tbl->num_entries)
return Qfalse;
+

  • data.tbl = RHASH(hash2)->tbl;
  • data.result = Qtrue;
  • st_foreach(RHASH(hash1)->tbl, equal_i, (st_data_t)&data);
  • return data.result;
    +}

+/*

    • call-seq:
    • hsh === other_hash    => true or false
      
    • Equality—Two hashes are strictly 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. Both hashes must have also equal default values/procs.
    • 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
      
  • */

+static VALUE
+rb_hash_strict_equal(hash1, hash2)

  • VALUE hash1, hash2;
    +{

  • struct equal_data data;

  • if (hash1 == hash2) return Qtrue;

  • if (TYPE(hash2) != T_HASH) {

  • if (!rb_respond_to(hash2, rb_intern(“to_hash”))) {

  •   return Qfalse;
    
  • }

  • return rb_equal(hash2, hash1);

  • }

  • if (RHASH(hash1)->tbl->num_entries != RHASH(hash2)->tbl->num_entries)

  • return Qfalse;
    if (!(rb_equal(RHASH(hash1)->ifnone, RHASH(hash2)->ifnone) &&
    FL_TEST(hash1, HASH_PROC_DEFAULT) == FL_TEST(hash2, HASH_PROC_DEFAULT)))
    return Qfalse;
    @@ -1435,7 +1477,6 @@

    return data.result;
    }

static int
rb_hash_invert_i(key, value, hash)
VALUE key, value;
@@ -2365,6 +2406,7 @@
rb_define_method(rb_cHash,“inspect”, rb_hash_inspect, 0);

 rb_define_method(rb_cHash,"==", rb_hash_equal, 1);
  • rb_define_method(rb_cHash,“===”, rb_hash_strict_equal, 1);
    rb_define_method(rb_cHash,“”, rb_hash_aref, 1);
    rb_define_method(rb_cHash,“fetch”, rb_hash_fetch, -1);
    rb_define_method(rb_cHash,“=”, rb_hash_aset, 2);

Hi,

  • Change ‘==’ method to compare only key-value pairs.
  • Add Hash#=== method to act like current Hash#==

They are possible options, along with

  • add new method (e.g. content_equal?) for membership equality.

I’m not sure which one is the best way to go.

   matz.

I think that most common case for == would be content equals and not
content and default value/proc equal.

Nobu has a good point that === would make more sense to be a
membership test, i.e., alias for Hash#key?.

Perhaps eql? would could be content equal and default value/block.
This would be similar Numeric where 1 == 1.0 is true but 1.eql?(1.0)
is false.

Thanks for listening,

Walt

···

In message “Re: Hash, ==, key-value comparison” > on 04/04/16, Elias Athanasopoulos elathan@phys.uoa.gr writes:


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


s/content_equal/equiv/ ?

-a

···

On Fri, 16 Apr 2004, Yukihiro Matsumoto wrote:

Hi,

In message “Re: Hash, ==, key-value comparison” > on 04/04/16, Elias Athanasopoulos elathan@phys.uoa.gr writes:

  • Change ‘==’ method to compare only key-value pairs.
  • Add Hash#=== method to act like current Hash#==

They are possible options, along with

  • add new method (e.g. content_equal?) for membership equality.

I’m not sure which one is the best way to go.

  					matz.

EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328
URL :: Solar-Terrestrial Physics Data | NCEI
TRY :: for l in ruby perl;do $l -e “print "\x3a\x2d\x29\x0a"”;done
===============================================================================

I tend to think about == as “has the same value as”.
So == is rather strong.
I like it this way, so I would rather stick with the exiting scheme.
OTOH I agree that the default value/proc is easy to miss. Yet,
maybe some other operator could do the job, something like ~= if available ?
Jean-Hugues

···

At 02:30 16/04/2004 +0900, you wrote:

On Fri, Apr 16, 2004 at 02:04:10AM +0900, walter@mwsewall.com wrote: >
Ok, > > ALthough the docs don’t mention it, Hash comparison using ==
checks > not only the key value pairs, but also the default value /
default > procs. > > So how does one compare 2 hashes key-value pairs.
I can see that it

I can contribute a patch to:

  • Change ‘==’ method to compare only key-value pairs.
  • Add Hash#=== method to act like current Hash#==

Comments?

Personally, I like the idea. You get my vote!

Regards,

University of Athens I bet the human brain
Physics Department is a kludge --Marvin Minsky

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


Bath, ME 04530 Fax : (207) 443-6284



Web: http://hdl.handle.net/1030.37/1.1
Phone: +33 (0) 4 92 27 74 17

Hi,

I feel Hash#=== would test membership, i.e., alias for
Hash#key?.


Nobu Nakada

I’d agree with that. This way you could easily test for many possible
values in a case statement.

Note that if there are many vaes to match with, then a hash may be
more efficent then a “when” with a comma-delimited list, as long as the
hash is calculated only once. (Of course, if there are multiple “when”
branches like that, a single hash that does all the matching or probably a
hash of proces or lambdas (I don’t quite know the fine point of
distinguishing these) is better.)

Let me mention how this will work in perl6. In perl6, the =~ operator will
do something similar to ruby’s ===, that is, it is used in the when clauses,
it matches numeric or string data, regexps, and classes just like === in
ruby (and thus does not automatically coerce a string to a regexp as =~ in
per5 or ruby). When it meets a hash or an array on either side, it mathces
each key (element of array) with the other side until it finds a match.
To do this with an array is quite unneccesarry I think, but it is good for a
haash.

···

On Fri, Apr 16, 2004 at 09:23:00AM +0900, nobu.nokada@softhome.net wrote:

My turn:

  • Hash#== compares only the data
  • Hash#equiv? compares the data and the proc
  • Hash#=== is alias for Hash#key?

The first two I think are matters of importance; the third one is just
a nice idea. There are probably other, equally good, ideas for
Hash#===.

Cheers,
Gavin

···

On Friday, April 16, 2004, 1:24:12 PM, Ara.T.Howard wrote:

On Fri, 16 Apr 2004, Yukihiro Matsumoto wrote:

  • Change ‘==’ method to compare only key-value pairs.
  • Add Hash#=== method to act like current Hash#==

They are possible options, along with

  • add new method (e.g. content_equal?) for membership equality.

I’m not sure which one is the best way to go.

s/content_equal/equiv/ ?

“Zsban Ambrus” ambrus@math.bme.hu schrieb im Newsbeitrag
news:20040417194736.GA1309@math.bme.hu…

Hi,

I feel Hash#=== would test membership, i.e., alias for
Hash#key?.


Nobu Nakada

I’d agree with that. This way you could easily test for many possible
values in a case statement.

Does this work? I mean

h = {}
case h
when val1, val2

end

Does something else: it tests val1 === h and val2 === h and not h === val1.
Currently I don’t see how Hash#=== can be used in a case to test for
multiple values. In order to use Hash#=== in a case statement, the hash has
to appear in the when clauses. Do I overlook something?

Regards

robert
···

On Fri, Apr 16, 2004 at 09:23:00AM +0900, nobu.nokada@softhome.net wrote:

No, I mean something like this:

bad= {}; # bad magic words that the player might try
%w[abracadabra xyzzy hocuspocus bringmehome].each do |x| bad=1 end;

this list of (bad) magic words might get very long

(in a loop)

gets
~/^\s*(\w+)/ and word= $1
case word
when bad
puts “That won’t work in this game. Nice try, thuogh.”
when “aardvark” # this is the real magic word
player.move(Home)
when “a”, “ahead”
player.move_ahead
when “fight”, “shoot”
(… check if there’s a monster here, kill it with 1/2 probability,
otherwise make it angry …)

end

···

On Sun, Apr 18, 2004 at 07:39:11PM +0900, Robert Klemme wrote:

“Zsban Ambrus” ambrus@math.bme.hu schrieb im Newsbeitrag
news:20040417194736.GA1309@math.bme.hu…

On Fri, Apr 16, 2004 at 09:23:00AM +0900, nobu.nokada@softhome.net wrote:

Hi,

I feel Hash#=== would test membership, i.e., alias for
Hash#key?.


Nobu Nakada

I’d agree with that. This way you could easily test for many possible
values in a case statement.

Does this work? I mean

h = {}
case h
when val1, val2

end

Does something else: it tests val1 === h and val2 === h and not h === val1.
Currently I don’t see how Hash#=== can be used in a case to test for
multiple values. In order to use Hash#=== in a case statement, the hash has
to appear in the when clauses. Do I overlook something?

Regards

robert

“Zsban Ambrus” ambrus@math.bme.hu schrieb im Newsbeitrag
news:20040418110453.GA2123@math.bme.hu…

“Zsban Ambrus” ambrus@math.bme.hu schrieb im Newsbeitrag
news:20040417194736.GA1309@math.bme.hu…

Hi,

I feel Hash#=== would test membership, i.e., alias for
Hash#key?.


Nobu Nakada

I’d agree with that. This way you could easily test for many
possible
values in a case statement.

Does this work? I mean

h = {}
case h
when val1, val2

end

Does something else: it tests val1 === h and val2 === h and not h ===
val1.
Currently I don’t see how Hash#=== can be used in a case to test for
multiple values. In order to use Hash#=== in a case statement, the
hash has
to appear in the when clauses. Do I overlook something?

Regards

robert

No, I mean something like this:

bad= {}; # bad magic words that the player might try
%w[abracadabra xyzzy hocuspocus bringmehome].each do |x| bad=1 end;

this list of (bad) magic words might get very long

(in a loop)

gets
~/^\s*(\w+)/ and word= $1
case word
when bad
puts “That won’t work in this game. Nice try, thuogh.”
when “aardvark” # this is the real magic word
player.move(Home)
when “a”, “ahead”
player.move_ahead
when “fight”, “shoot”
(… check if there’s a monster here, kill it with 1/2 probability,
otherwise make it angry …)

end

Ah, ok I see. Thx! I like especially the “when bad”. :slight_smile:

robert
···

On Sun, Apr 18, 2004 at 07:39:11PM +0900, Robert Klemme wrote:

On Fri, Apr 16, 2004 at 09:23:00AM +0900, nobu.nokada@softhome.net wrote: