Can I create a collection in Scala that uses different equals/hashCode/compare implementations?
-
27-09-2019 - |
Question
I'm looking for as simple way to create an identity set. I just want to be able to keep track of whether or not I've "seen" a particular object while traversing a graph.
I can't use a regular Set because Set uses "==" (the equals method in Scala) to compare elements. What I want is a Set that uses "eq."
Is there any way to create a Set in Scala that uses some application-specified method for testing equality rather than calling equals on the set elements? I looked for some kind of "wrapEquals" method that I could override but did not find it.
I know that I could use Java's IdentityHashMap, but I'm looking for something more general-purpose.
Another idea I had was to just wrap each set element in another object that implements equals in terms of eq, but it's wasteful to generate tons of new objects just to get a new equals implementation.
Thanks!
Solution
This is a similar question. The accepted answer in that case was to use a TreeSet
and provide a custom Comparator
.
OTHER TIPS
Depending on your needs you could create a box for which you use identity checks on the contained element such as:
class IdentBox[T <: AnyRef](val value: T) {
override def equals(other: Any): Boolean = other match {
case that: IdentBox[T] => that.value eq this.value
case _ => false
}
override def hashCode(): Int = value.hashCode
}
And make the collection to contain those boxes instead of the elements directly: Set[IdentBox[T]]
It has some overhead of boxing / unboxing but it might be tolerable in your use case.
Since you don't require a reference to the "seen" objects, but just a boolean value for "contains", I would suggest just using a mutable.Set[Int]
and loading it with values obtained by calling System.identityHashCode(obj)
.
Scala custom collections have enough conceptual surface area to scare off most people who want a quick tweak like this.