Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java - How to find matching objects between two lists?

Given two Lists, each list holding the same object type, I would like to find objects between the two lists that match, based on some property values.

e.g. an object from List1, L1Obj, matches an object from List2, L2Obj, if L1Obj.a == L2Obj.a AND L1Obj.b == L2Obj.c AND L1Obj.c == L2Obj.c

These properties are not the only properties of the of the class, but are all that is needed to uniquely identify an object within a list.

My question is - what is the best way to achieve this?

One way would be to construct to HashMaps based on the lists, with the concataned String value of a+b+c used as the key to index an object. That way I could iterate through the first list, and attempt to lookup an object in the second list with the same key.

How does this sound? Is there a better way of achieving this??

All help is much appreciated!


UPDATE:

Okay, so actually I need a bit more. Upon finding a match, I want to overwrite properties L1Obj.x, L1Obj.y, L1Obj.z with those of L2Obj. HashSet sounds great for finding that matches, but if I'm right it doesn't actually allow me to access these matches.

What can I do about this?

like image 820
QuakerOat Avatar asked Feb 15 '11 23:02

QuakerOat


3 Answers

Do the objects you want to look at implement equals(Object) and hashCode() that only take into account the fields you care about? If so, you can create a new HashSet from the first list, and then call retainAll() passing in the second list.

If they don't implement equals(Object) and hashCode() with respect to the properties you care about, you can create a TreeSet and pass in a Comparator that looks at the properties you care about.

like image 98
ILMTitan Avatar answered Nov 11 '22 14:11

ILMTitan


Rather than use the String repesntation, use the equals() method a HashSet as so:

class MyObj {

    Property a;
    Property b;
    Property c;

    public boolean equals(Object o) {
        // use == if Property is primitive, like int or something
        return o instanceof MyObj && a.equals(o.a) && b.equals(o.b) && c.equals(o.c);
    }

    // edit - when you override equals, also override hashcode
    public int hashCode() {
        return a.hashCode() ^ b.hashCode() ^ c.hashCode();
    }

    public String toString() {
        return a.toString() + " " + b.toString() + " " + c.toString();
    }

}

// later in your main method
Set<MyObj> objSet = new HashSet<MyObj>();
for(MyObj o : list1) objSet.add(o);
for(MyObj o : list2) if(objSet.contains(o)) System.out.println(o + " is a match!");
like image 3
corsiKa Avatar answered Nov 11 '22 13:11

corsiKa


You can do one thing. Have two lists with these objects and override the equals method of the class to which these objects belong. Your equals method should look like

@Override
public boolean equals(Object obj)
{
    return (this.a == obj.a && this.b == obj.b && this.c == obj.c)

}

Also remember, once you override equals method, you need to override int hashCode() method as well.

One thing to note is while implementing hashCode() is that 2 equal objects will have same hashCode, while the converse is not true.

like image 1
Chander Shivdasani Avatar answered Nov 11 '22 13:11

Chander Shivdasani