[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

[?] problem using set with hash objects

Stephen Bannasch

9/17/2007 8:06:00 PM

I'm using set in the ruby standard library to produce collections of
unique objects from enumerable objects with duplicates but it's
doesn't appear to work with hash objects.

$ ruby --version
ruby 1.8.5 (2006-12-25 patchlevel 12) [i686-darwin8.9.1]
$ irb
irb(main):001:0> require 'set'
=> true
irb(main):002:0> a = [1,1,2,3]
=> [1, 1, 2, 3]
irb(main):003:0> b = [{:a1 => "123"}, {:a1 => "123"}, {:b1 => "123"}]
=> [{:a1=>"123"}, {:a1=>"123"}, {:b1=>"123"}]
irb(main):004:0> seta = a.to_set
=> #<Set: {1, 2, 3}>
irb(main):005:0> setb = b.to_set
=> #<Set: {{:a1=>"123"}, {:a1=>"123"}, {:b1=>"123"}}>
irb(main):006:0> b[0] == b[1]
=> true

Am I doing something wrong?

1 Answer

Stefano Crocco

9/17/2007 8:29:00 PM

0

Alle lunedì 17 settembre 2007, Stephen Bannasch ha scritto:
> I'm using set in the ruby standard library to produce collections of
> unique objects from enumerable objects with duplicates but it's
> doesn't appear to work with hash objects.
>
> $ ruby --version
> ruby 1.8.5 (2006-12-25 patchlevel 12) [i686-darwin8.9.1]
> $ irb
> irb(main):001:0> require 'set'
> => true
> irb(main):002:0> a = [1,1,2,3]
> => [1, 1, 2, 3]
> irb(main):003:0> b = [{:a1 => "123"}, {:a1 => "123"}, {:b1 => "123"}]
> => [{:a1=>"123"}, {:a1=>"123"}, {:b1=>"123"}]
> irb(main):004:0> seta = a.to_set
> => #<Set: {1, 2, 3}>
> irb(main):005:0> setb = b.to_set
> => #<Set: {{:a1=>"123"}, {:a1=>"123"}, {:b1=>"123"}}>
> irb(main):006:0> b[0] == b[1]
> => true
>
> Am I doing something wrong?

According to the ri documentation, Set internally stores items in a hash.
Because of this, it uses the eql? and hash methods, and not ==, to test
objects for equality. Hash#eql? (actually, Kernel#eql?) only returns true if
two objects are the same object. Since b[0] and b[1] are different objects,
Set considers them not equal, and thus stores them both. If you put the same
hash in two places of the array you convert to a set, only one of them will
be kept:

irb: 001> require 'set'
true
irb: 002> h = {'a' => 1, 'b' => 2}
{"a"=>1, "b"=>2}
irb: 003> a = [h, {'c' => 3}, h]
[{"a"=>1, "b"=>2}, {"c"=>3}, {"a"=>1, "b"=>2}]
irb: 004> a.to_set.size
2
irb: 005> p a.to_set
#<Set: {{"a"=>1, "b"=>2}, {"c"=>3}}>

Other classes, instead, provide their own definition of eql?, which leads to
different (often less surprising) results. For instance, Array#eql? returns
true if the two arrays have the same elements. String do the same.

I hope this helps

Stefano