Set#== ain't

While writing an acceptance test, I needed to compare two sets of sets
of integers:

require 'set'
a = Set.new([Set.new([3,4]), Set.new([5,6])])
b = Set.new([Set.new([3,4]), Set.new([5,6])])
puts #{a == b}\n"

prints out 'false'.

Apparently the built-in Set library uses Hash#includes? to determine if
an object is in the rhs set. This method appears to use object id, so
set equality is based on set member object id.

A naive #==(set) that works the way I think it should is pretty simple:

def Set.my_eql?(set)
  ...
  # this is the only part of my_eql? that differs from #==(set),
  # replacing the line 'set.all? { |o| hash.include?(o) }'

  set.all? { |o|
    @hash.each_value do |my_o|
      if my_o == o
        last true
      end
      false
    end
  }
end

I'm sure this has come up before... is there a better solution? This
one is fine for my purposes, but I would be nice there was a packaged
solution out there.

    Gary

Hi --

While writing an acceptance test, I needed to compare two sets of sets
of integers:

require 'set'
a = Set.new([Set.new([3,4]), Set.new([5,6])])
b = Set.new([Set.new([3,4]), Set.new([5,6])])
puts #{a == b}\n"

prints out 'false'.

Apparently the built-in Set library uses Hash#includes? to determine if
an object is in the rhs set. This method appears to use object id, so
set equality is based on set member object id.

A naive #==(set) that works the way I think it should is pretty simple:

def Set.my_eql?(set)

You'd want that to be an instance method, not a class method:

   class Set
     def my_eql?(set)

...
# this is the only part of my_eql? that differs from #==(set),
# replacing the line 'set.all? { |o| hash.include?(o) }'

set.all? { |o|
   @hash.each_value do |my_o|
     if my_o == o
       last true
     end
     false
   end
}
end

You could just do:

     set.all? {|x| any? {|y| x == y } }

I'm sure this has come up before... is there a better solution? This
one is fine for my purposes, but I would be nice there was a packaged
solution out there.

It did come up, quite recently I think. I can't remember what the
consensus was, if any.

David

···

On Thu, 22 Sep 2005, Gary Shea wrote:

--
David A. Black
dblack@wobblini.net

Hi --

> While writing an acceptance test, I needed to compare two sets of sets
> of integers:
>
> require 'set'
> a = Set.new([Set.new([3,4]), Set.new([5,6])])
> b = Set.new([Set.new([3,4]), Set.new([5,6])])
> puts #{a == b}\n"
>
> prints out 'false'.
>
> Apparently the built-in Set library uses Hash#includes? to determine if
> an object is in the rhs set. This method appears to use object id, so
> set equality is based on set member object id.
>
> A naive #==(set) that works the way I think it should is pretty simple:
>
> def Set.my_eql?(set)

You'd want that to be an instance method, not a class method:

   class Set
     def my_eql?(set)

Whoops :slight_smile:

> ...
> # this is the only part of my_eql? that differs from #==(set),
> # replacing the line 'set.all? { |o| hash.include?(o) }'
>
> set.all? { |o|
> @hash.each_value do |my_o|
> if my_o == o
> last true
> end
> false
> end
> }
> end

You could just do:

     set.all? {|x| any? {|y| x == y } }

Wow, that's almost mathematical set notation! Nice.

···

On Thu, 2005-09-22 at 02:16 +0900, David A. Black wrote:

On Thu, 22 Sep 2005, Gary Shea wrote:

> I'm sure this has come up before... is there a better solution? This
> one is fine for my purposes, but I would be nice there was a packaged
> solution out there.

It did come up, quite recently I think. I can't remember what the
consensus was, if any.

David

The above solution of set.all? {|x| any? { |y| x== y} } is not a full
solution. This will only work if you have set-nesting as described in
the original problem, but not if you have higher nesting (because then
you run back into the same original problem except one nesting level
down).

If this was the actual definition of ==, then it would work of course
:).