Alle luned=EC 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'

=3D> true

irb(main):002:0> a =3D [1,1,2,3]

=3D> [1, 1, 2, 3]

irb(main):003:0> b =3D [{:a1 =3D> "123"}, {:a1 =3D> "123"}, {:b1 =3D> "12= 3"}]

=3D> [{:a1=3D>"123"}, {:a1=3D>"123"}, {:b1=3D>"123"}]

irb(main):004:0> seta =3D a.to_set

=3D> #<Set: {1, 2, 3}>

irb(main):005:0> setb =3D b.to_set

=3D> #<Set: {{:a1=3D>"123"}, {:a1=3D>"123"}, {:b1=3D>"123"}}>

irb(main):006:0> b[0] =3D=3D b[1]

=3D> true

Am I doing something wrong?

According to the ri documentation, Set internally stores items in a hash.=20

Because of this, it uses the eql? and hash methods, and not =3D=3D, to test=

=20

objects for equality. Hash#eql? (actually, Kernel#eql?) only returns true i=

f=20

two objects are the same object. Since b[0] and b[1] are different objects,=

=20

Set considers them not equal, and thus stores them both. If you put the sam=

e=20

hash in two places of the array you convert to a set, only one of them will=

=20

be kept:

irb: 001> require 'set'

true

irb: 002> h =3D {'a' =3D> 1, 'b' =3D> 2}

{"a"=3D>1, "b"=3D>2}

irb: 003> a =3D [h, {'c' =3D> 3}, h]

[{"a"=3D>1, "b"=3D>2}, {"c"=3D>3}, {"a"=3D>1, "b"=3D>2}]

irb: 004> a.to_set.size

2

irb: 005> p a.to_set

#<Set: {{"a"=3D>1, "b"=3D>2}, {"c"=3D>3}}>

Other classes, instead, provide their own definition of eql?, which leads t=

o=20

different (often less surprising) results. For instance, Array#eql? returns=

=20

true if the two arrays have the same elements. String do the same.

I hope this helps

Stefano