Remove duplicates without overriding hash method
I have a List that contains a list of objects, and I want to remove from this list all elements that have the same value in their two attributes. I had something like this:
List<Class1> myList;
....
Set<Class1> mySet = new HashSet<Class1>();
mySet.addAll(myList);
and overriding the hash method in Class1 so it returns a number that only depends on the attributes I want to consider.
The problem is that I need to do different filtering in a different part of the application, so I cannot override the hash method this way (I need two different hash methods).
What's the most efficient way to do this filtering without overriding the hash method?
thanks
a source to share
Overriding hashCode
and equals
in Class1
(only for this) is problematic. You end up with a class that has an unnatural definition of equality, which may differ for other current and future uses of the class.
Review the Comparator interface and write an implementation Comparator<Class1>
to compare instances of yours Class1
based on your criteria; for example based on these two attributes. Then instantiate TreeSet<Class
> `to re-discover using the TreeSet (Comparator) constructor .
EDIT
Comparing this approach to @ Tom Hawtin's:
-
Both approaches use roughly comparable space overall. The inner nodes of the treeet will roughly balance the hashset array and wrappers that support custom equals / hash methods.
-
Wrapping method + hashset
O(N)
over time (assuming good hashing) versusO(NlogN)
for the trees approach. So this is the way to go if the input list is likely to be large. -
The tree approach wins in terms of the lines of code that need to be written.
a source to share
As an alternative to what Roman said, you can take a look at this SO question about filtering using Predicates. If you are using google collection anyway this might come in handy.
a source to share
Sometimes programmers do too complex things, trying to use all the nice features of the language, and the answers to this question are examples. Overriding anything in the class is overkill. You need the following:
class MyClass {
Object attr1;
Object attr2;
}
List<Class1> list;
Set<Class1> set=....
Set<MyClass> tempset = new HashSet<MyClass>;
for (Class1 c:list) {
MyClass myc = new MyClass();
myc.attr1 = c.attr1;
myc.attr2 = c.attr2;
if (!tempset.contains(myc)) {
tempset.add(myc);
set.add(c);
}
}
Feel free to commit minor irregularities. There will be some problems depending on what you mean by equality for attributes (and obvious changes if attributes are primitive). Sometimes we need to write code and not just use built-in libraries.
a source to share