Reputation: 1108
I have a class Attribute which has 2 variables say int a,b;
I want to use class Attribute in two different HashSet.
The first hash set considers objects as equal when the value of a is same. But the second hash set considers objects as equal when the value of b is same.
I know if I override the equals method the hashset will use the overriden version of equals to compare two objects but in this case I would need two different implementations of equals()
One way is to create two subclasses of attribute and provide them with different equals method but I want to know if there is a better way to do it such that I dont have to create subclass of Attribute.
Thanks.
Upvotes: 0
Views: 465
Reputation: 1108
I did some thing different, Instead of using the HashSet, I have used HashMap where I have used int a as a key in first HashMap and the object is stored as value. And in the other HashMap I have kept the key as int b and the object as value.
This provides me a way to Hash on both the variables a and b so I dont have to make any sub classes.
And also, I get O(1) time instead of O(log n). But I know I am paying the price by using some more memory but my main concern was time so I chose HashMap over TreeSet.
Thank you all for your comments and suggestions.
Upvotes: 1
Reputation: 7964
I can propose a bit hacky but lesser effort solution :) Swap the values of a and b when storing in second hashset so that uniqueness is defined by value of b and then when reading the class from hashset then swap the value of a and b again to retain the original state. So the same equals/hascode methods will serve the purpose.
Upvotes: 0
Reputation: 36562
A simple solution is to bypass HashSet
and use HashMap
directly. For the first, store each Attribute
using its a
property as the key, and for the other use b
.
Upvotes: 0
Reputation: 36562
It would be very easy to modify HashMap
and HashSet
to accept hashing and equality-testing strategies.
public interface Hasher {
int hashCode(Object o);
}
public interface Equalizer {
int areEqual(Object o1, Object o2);
}
Upvotes: 0
Reputation: 13922
One possible solution is to not use HashSet
, but use TreeSet
instead. It's the same Set
interface, but there is a TreeSet
constructor that lets you pass in a Comparator
. That way you could leave the Attribute
class unchanged- just create two different comparators and use it like
Set<Attribute> setA = new TreeSet<Attribute>(comparatorForA);
Set<Attribute> setB = new TreeSet<Attribute>(comparatorForB);
The comparator takes care of the equality check (e.g. if compare
returns 0, the objects are equal)
Upvotes: 3
Reputation: 12009
Unfortunately there's no "Equalizer" class that can override the equals
logic. There is such a thing for sorting, where you can either use natural sorting based on the Comparable
implementation or provide your own Comparator
. I've actually wondered why there's no such thing for equality checks.
Since the semantics of equality are defined by a class and could be considered a trait of that class, the two subclasses approach seems the most natural. Maybe someone knows a useful pattern for doing this in a more simple manner, but I've never encountered it.
EDIT: just thought of something... you could use two Map
instances, like HashMap
, with the first one using a
as key and the second using b
as key. It'd let you detect collisions. You could then simply link the attribute to the associated instance.
Upvotes: 1