Java set with multiple equality criteria

I have a special requirement when I need to deduce a list of objects based on a combination of equality criteria.

eg. Two Student objects are equal if:
1. firstName and id are the same OR 2. lastName, class and emailId are the same

I planned to use Set to remove duplicates. However, there is a problem:
I can override the equals method, but the hashCode method may not return the same hash code for two equal objects.

 @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Student other = (Student) obj; if ((firstName.equals(other.firstName) && id==other.id) || (lastName.equals(other.lastName) && class==other.class && emailId.equals(other.emailId )) return true; return false; } 

Now I can not redefine the hashCode method so that it returns the same hash codes for two objects that are equal according to this equals method.

Is there a way to deduplicate based on multiple criteria of equality? I examined the use of List and then using the contains method to check if this element exists, but this increases complexity because it contains runs in O (n) time. I do not want to return the same hash codes for all objects, as this simply increases the time and exceeds the purpose of using hash codes. I also looked at sorting items using a custom comparator, but again it takes at least O (n log n), plus another walk to remove duplicates.

Currently, the best solution is to save two different sets, one for each condition, and use this to build a List , but it takes almost three times as much memory. I am looking for a faster and more efficient way of memory, as I will deal with a large number of entries.

+4
source share
2 answers

You can make Student Comparable and use TreeSet . A simple implementation of compareTo could be:

 @Override public int compareTo(Student other) { if (this.equals(other)) { return 0; } else { return (this.firstName + this.lastName + emailId + clazz + id) .compareTo(other.firstName + other.lastName + other.emailId + clazz + id); } } 

Or create your own implementation of Set , for example, containing a List various Student objects, checking equality each time you add a student. This will have O(n) complexity, so it cannot be considered a good implementation, but it is easy to write.

 class ListSet<T> extends AbstractSet<T> { private List<T> list = new ArrayList<T>(); @Override public boolean add(T t) { if (list.contains(t)) { return false; } else { return list.add(t); } } @Override public Iterator<T> iterator() { return list.iterator(); } @Override public int size() { return list.size(); } } 
0
source

You can see this problem as an attempt to find objects that are equal in terms of business , but still different records. Therefore, do not redefine equals or hashCode so that it violates such an important rule:

If two objects are equal according to the equals (Object) method, then calling the hashCode method on each of the two objects should have the same integer result.

Instead, use a Set implementation that ignores hashCode and allows you to use a custom Comparator . See the accepted answer in TreeSet and hashCode () .

0
source

All Articles