Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compare different object types with comparator

I need to write a Comparator that take an object A of type A and an object B of type B. The two object are not an extention of a common object. They are really diffferent, but I need to compare this two object by common fields in it. I have to use the comparator interface because the objects are stored in Set and after I have to do operations with CollectionUtils. I googled a little bit arround and I find solutions with Comparator but only with the same type.

I tried to implement a think in this direction but I don't know If I'm very on the correct way.

public class MyComparator implements Comparator<A>, Serializable {

  private B b;

  public MyComparator(B b){
       this.b = b;
  }

  @Override
  public int compare(A old, A otherOne) {
    int value = 0;
    if (!old.getField().equals(b.getField())) {
        value = 1;
    }
    return value;
  }
}

It's possible that an answer is always given, but I did not found the right words to search in Google. Have someone suggestions?

Txs

P.S: I add the two objects in diferent Set:

TreeSet<A> setA = new TreeSet<A>(myComparator);
TreeSet<B> setB = new TreeSet<B>(myComparator);

and after I would do thinks like this:

TreeSet<??????> retain = CollectionUtils.retainAll(setA, setB);
TreeSet<??????> remove = CollectionUtils.removeAll(setA, setB);
like image 717
code4fun Avatar asked Feb 16 '15 10:02

code4fun


2 Answers

There's a very hacky way of doing it that allows you to use Object and instanceof but if you can implement a proxy class that exposes a specific interface you would be better off doing that.

class A {

    public String getSomething() {
        return "A";
    }
}

class B {

    public String getSomethingElse() {
        return "B";
    }
}

class C implements Comparator<Object> {

    @Override
    public int compare(Object o1, Object o2) {
        // Which is of what type?
        A a1 = o1 instanceof A ? (A) o1: null;
        A a2 = o2 instanceof A ? (A) o2: null;
        B b1 = o1 instanceof B ? (B) o1: null;
        B b2 = o2 instanceof B ? (B) o2: null;
        // Pull out their values.
        String s1 = a1 != null ? a1.getSomething(): b1 != null ? b1.getSomethingElse(): null;
        String s2 = a2 != null ? a2.getSomething(): b2 != null ? b2.getSomethingElse(): null;
        // Compare them.
        return s1 != null ? s1.compareTo(s2): 0;
    }

}

The more acceptable mechanism would be to implement a proxy class for each that implements a common interface tyhat can then be compared using a proper type-safe comparator.

interface P {

    public String getValue();
}

class PA implements P {

    private final A a;

    PA(A a) {
        this.a = a;
    }

    @Override
    public String getValue() {
        return a.getSomething();
    }
}

class PB implements P {

    private final B b;

    PB(B b) {
        this.b = b;
    }

    @Override
    public String getValue() {
        return b.getSomethingElse();
    }
}

class PC implements Comparator<P> {

    @Override
    public int compare(P o1, P o2) {
        return o1.getValue().compareTo(o2.getValue());
    }

}
like image 180
OldCurmudgeon Avatar answered Sep 30 '22 08:09

OldCurmudgeon


If you store objects of the two unrelated types in a Set (which makes me wonder, since Sets are usually unordered), this means you are using a raw Set, which is not very type safe.

You can define an interface CommonAB that contains getter methods for all the common properties of A and B. Both A and B will implement that interface. You'll be able to put instances of A and B in a Set<CommonAB>.

Finally, a Comparator<CommonAB> will be able to compare objects of both types. The Comparator will access only the methods of the interface. It won't care if it's comparing two As, two Bs or an A and a B.

like image 39
Eran Avatar answered Sep 30 '22 07:09

Eran