2

I have two array list. Each has list of Objects of type User.

The User class looks like below

    public class User {

    private long id;

    private String empCode;

    private String firstname;

    private String lastname;

    private String email;

    public User( String firstname, String lastname, String empCode, String email) {
        super();
        this.empCode = empCode;
        this.firstname = firstname;
        this.lastname = lastname;
        this.email = email;
    }

    // getters and setters

}


    import java.util.ArrayList;
import java.util.List;

public class FindSimilarUsersWithAtLeastOneDifferentProperty {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub

        List<User> list1 = new ArrayList<User>();

        list1.add(new User("F11", "L1", "EMP01", "u1@test.com"));
        list1.add(new User("F2", "L2", "EMP02", "u222@test.com"));
        list1.add(new User("F3", "L3", "EMP03", "u3@test.com"));
        list1.add(new User("F4", "L4", "EMP04", "u4@test.com"));
        list1.add(new User("F5", "L5", "EMP05", "u5@test.com"));
        list1.add(new User("F9", "L9", "EMP09", "u9@test.com"));
        list1.add(new User("F10", "L10", "EMP10", "u10@test.com"));

        List<User> list2 = new ArrayList<User>();

        list2.add(new User("F1", "L1", "EMP01", "u1@test.com"));
        list2.add(new User("F2", "L2", "EMP02", "u2@test.com"));
        list2.add(new User("F6", "L6", "EMP06", "u6@test.com"));
        list2.add(new User("F7", "L7", "EMP07", "u7@test.com"));
        list2.add(new User("F8", "L8", "EMP08", "u8@test.com"));
        list2.add(new User("F9", "L9", "EMP09", "u9@test.com"));
        list2.add(new User("F100", "L100", "EMP10", "u100@test.com"));

        List<User> resultList = new ArrayList<User>();
        // this list should contain following users
        // EMP01 (common in both list but differs in firstname)
        // EMP02 (common in both list but differs in email)
        // EMP10 (common in both list but differs in firstname, lastname and email)


    }

}

If you see the sample code, the two lists have four users with emp code EMP01, EMP02, EMP09 and EMP10 common.

So, we only need to compare the properties of these four users.

If any of the users have at least one different property it should be added in the result list.

Please advise on how do I go about this?

ajm
  • 12,863
  • 58
  • 163
  • 234
  • The resutList contain both of the similar users? – Bhesh Gurung Oct 12 '12 at 06:08
  • @Bhesh Gurung. No just the users from the list 1. – ajm Oct 12 '12 at 06:09
  • What about the empcode, do they need to match? – Bhesh Gurung Oct 12 '12 at 06:10
  • @Bhesh Gurung. We need to compare users of matching emp codes only. So, if list 1 has emp code e1 and list 2 also have emp code e1, then only we need to compare their properties. If emp codes differ even with same name, they should not be matched. So, just see two lists, see common emp codes and then compare their prioperties. – ajm Oct 12 '12 at 06:13

6 Answers6

7

Implement equals, hashcode in User

    @Override
    public boolean equals(Object obj) {
        if (obj == null)
            return false;
        if (!(obj instanceof User))
            return false;
        User u = (User) obj;
        return this.empCode == null ? false : this.empCode
                .equals(u.empCode);
    }

    @Override
    public int hashCode() {
        return this.empCode == null ? 0 : this.empCode.hashCode();
    }

    @Override
    public String toString() {
        return "Emp Code: " + this.empCode;
    }

Then use retainAll

list2.retainAll(list1);-->EMP01, EMP02, EMP09, EMP10
Amit Deshpande
  • 19,001
  • 4
  • 46
  • 72
  • You are not comparing all the properties. It should not be the exact duplicate. – Bhesh Gurung Oct 12 '12 at 06:44
  • If EmpId is business key and it guarantees uniqueness then I don't have to. – Amit Deshpande Oct 12 '12 at 06:46
  • But what about, what the OP is looking for? – Bhesh Gurung Oct 12 '12 at 06:50
  • Using the key only for `equals` is bound to **creep up as an error** later on. If you want to compare for key equality, use the equality function of the key, or a list/hashmap based on the key. But the next developer probably assumes that `equals` tests *all* attributes. I'd almost give you a -1 for this **abuse of equals**, but on the other hand I like the reference to retainAll. – Has QUIT--Anony-Mousse Oct 12 '12 at 08:09
5

I think this what you should do -

for(User user1 : list1) {
    for(User user2 : list2) {
        if(user1.getEmpCode().equals(user2.getEmpCode())) {
            if(!user1.getFirstName().equals(user2.getFirstName()) ||
               !user1.getLastName().equals(user2.getLastName()) ||
               !user1.getEmail().equals(user2.getEmail())) {
                resultList.add(user1);
            }
        }
    }
}

It might not make sense for the User to override equal and hashCode only to serve this purpose. They should be overriden in the way in which it makes more sense domain-wise.

Bhesh Gurung
  • 50,430
  • 22
  • 93
  • 142
  • Overriding equals and hashcode and even what you are suggesting is working. I also agree to the fact that 'It might not make sense for the User to override equal and hashCode only to serve this purpose'. But if list1 and list2 are large like each list with say 1000 object. and If I compare ten properties, would it affect the perfomance. – ajm Oct 12 '12 at 06:36
  • It's not going to happen without iteration, whatever you choose. Performance wise they should be almost same. – Bhesh Gurung Oct 12 '12 at 06:39
3

This is simple. Override equal method in your User class. One very simple implementation(you can enhance it by using null checks etc) can be like below:

@override
public boolean equals(Object obj) {
User other = (User) obj;
    if(this.id==other.id 
      && this.empCode.equals(other.empCode)
      && this.firstname.equals(other.firstname)
      && this.lastname.equals(other.lastname)
      && this.email.equals(other.email)){
          return true;
    }else{
        return false;
    }
}

Once done, you can use:

 for(user user: list1){
    if(!resultList.contains(user)){
       resultList.add(user);
    }
 }


 for(user user: list2){
    if(!resultList.contains(user)){
       resultList.add(user);
    }
 }
Yogendra Singh
  • 33,927
  • 6
  • 63
  • 73
2

The canonical approach is as follows:

  1. Write a method countDifferences that counts the number of differences between users
  2. For each object in one list, find the minimum when compared to the other lists objects
  3. Report all objects where the minimum is not 0.

If you put weights on the different properties you can also control that e.g. a match in the ID attribute is stronger than a match in the name.

Update: sorry, misread your comment that the ID attribute must match.

Replace 2) with "find object which has the same ID". Other than that, I still recommend counting the number of differences. It is more flexible, as you can define thresholds for good or bad matches etc.

Has QUIT--Anony-Mousse
  • 76,138
  • 12
  • 138
  • 194
2

Add this method to your User class:

public boolean isSimilarButNotEqual(User other) {
        if(!this.empCode.equals(other.empCode))
            return false;
        return !(this.firstname + this.lastname + this.email).equals(other.firstname + other.lastname + other.email);
    }

Then, in the main() do:

   for(User user1: list1){          
        for(User user2: list2){         
            if(user1.isSimilarButNotEqual(user2)){
                resultList.add(user1);
                resultList.add(user2);                  
            }
        }
    }
RGO
  • 4,586
  • 3
  • 26
  • 40
2

I have used the following way to compare two custom ArrayList.

List<SinglePostData> allPosts = new ArrayList<>();
List<SinglePostData> noRepeatAllPosts = new ArrayList<>();

for (int i = 0; i < allPosts.size(); i++) {
    boolean isFound = false;
    for (int j = i+1; j < allPosts.size(); j++) {
        if (allPosts.get(i).getTitle().equals(allPosts.get(j).getTitle())) {
            isFound = true;
            break;
        }
    }
    if (!isFound) noRepeatAllPosts.add(allPosts.get(i));
}
Tunaki
  • 132,869
  • 46
  • 340
  • 423
AndroidBeginner
  • 663
  • 1
  • 9
  • 16