Array.uniq does not use ==?

I have a user defined object, Agent. And I want to pass my Agents around in
an Array. I’ve “mixed-in” the Comparable module, and defined <=> within
the class for sorting purposes. However, I also want to be able to
perform Array.uniq/Array.uniq! as well, having the decision on the
"uniqueness" of the object derived from one particular attribute.

My first thought was that all I need to do was define == in my Agent, and I
had hoped/assumed that this was the operator/function that Array.uniq looked
at when it executed. However, this is not the case. My next thought was
that Array.uniq might use <=>, and consider them “equal” if this returned 0,
however this was not the case either.

I have tried defining the following for my object:

<=>

···

==

eql?
equal?

but none of them seem to be used in the Array.uniq comparison. Further
investigation showed that a combination of overriding eql?() and hash() will
do the trick (are these both used in uniq?). Now, I know that I can
create my own class which inherits from Array, and override the uniq and
uniq! funciton to do what I want, but it seems like there is a less clumsly
solution (it just seems like I shouldn’t have to override hash()). Any
suggestions? Thanks.

Matt


Protect your PC - get McAfee.com VirusScan Online
http://clinic.mcafee.com/clinic/ibuy/campaign.asp?cid=3963

I think the answer depends on the characteristics of the Agent object.

Can you use a Set to hold your Agents? Depending on what the class of
the Agent is, each instance might be treated as a separate object
even if two Agent objects have the same attributes (for example, this
is true for Set objects within a Set object). If this is the case,
uniqueness on the basis of attributes could be determined something
like this:

Deletes objects with duplicate attributes from the calling set. Used

to deal with a

set object being able to contain two different set objects that have

the same elements.
def unique_attributes!
s =
self.each { |e|
if s.include?(e.inspect)
self.delete(e)
s.push(e.inspect)
else
s.push(e.inspect)
end
}
self
end

Note that you would need to separately define a unique_attributes to
take (set = self.dup) for the non-mutating version.

This method could also be adapted if you have to use Arrays and can’t
use Sets.

Other additional set methods are at:

Regards,

Mark

···

On Monday, June 9, 2003, at 02:43 PM, Orion Hunter wrote:

I have a user defined object, Agent. And I want to pass my Agents
around in an Array. I’ve “mixed-in” the Comparable module, and
defined <=> within the class for sorting purposes. However, I also
want to be able to perform Array.uniq/Array.uniq! as well, having the
decision on the “uniqueness” of the object derived from one particular
attribute.

[snip]

“Orion Hunter” orion2480@hotmail.com schrieb im Newsbeitrag
news:BAY2-F14247qXLFfJNw00027a03@hotmail.com

I have a user defined object, Agent. And I want to pass my Agents
around in
an Array. I’ve “mixed-in” the Comparable module, and defined <=>
within
the class for sorting purposes. However, I also want to be able to
perform Array.uniq/Array.uniq! as well, having the decision on the
“uniqueness” of the object derived from one particular attribute.

My first thought was that all I need to do was define == in my Agent,
and I
had hoped/assumed that this was the operator/function that Array.uniq
looked
at when it executed. However, this is not the case. My next thought
was
that Array.uniq might use <=>, and consider them “equal” if this
returned 0,
however this was not the case either.

I have tried defining the following for my object:

<=>

===
eql?
equal?

but none of them seem to be used in the Array.uniq comparison. Further
investigation showed that a combination of overriding eql?() and hash()
will
do the trick (are these both used in uniq?). Now, I know that I can
create my own class which inherits from Array, and override the uniq and
uniq! funciton to do what I want, but it seems like there is a less
clumsly
solution (it just seems like I shouldn’t have to override hash()). Any
suggestions? Thanks.

Yes, you have to override method hash(). The only clean solution if you
want to implement equivalence for a given class is to implement eql?, ==
and hash the way you need it. If you need ordering, too, you also have to
implement <=>. Of course you can implement those in terms of each other
minimizing the effort.

See here for some remarks and examples:

Cheers

robert