0

I have 2 ArrayList. And I want elements with common phone.

ArrayList<Contact> phone_contacts;
ArrayList<Contact> registered_users;

I used below method to get common elements:

ArrayList<Contact> common_contacts = new ArrayList<Contact>(phone_contacts);
common_contacts.retainAll(registered_users);

But, the result I get is empty. How can I get common phone contact in common_contacts ArrayList?

Contact

public class Contact {
    private String name;
    private String phone;

    public Contact(String name, String phone) {
        this.name = name;
        this.phone = phone;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }
}
4
  • You need to override proper equals() and hashcode() implementations in Contact class to make this work. JVM uses equals() implementation to compare two objects are same or not. Commented Jun 10, 2016 at 16:20
  • @Nambari: How can I do that? I am new in java. Commented Jun 10, 2016 at 16:21
  • javaworld.com/article/2073330/… might be good example/ Commented Jun 10, 2016 at 16:22
  • You can clone array list in java. Commented Jun 10, 2016 at 16:25

3 Answers 3

2

First, if you are treating a phone number as an identifier, I would advise caution. Falsehoods Programmers Believe About Phone Numbers

With that said...

retainAll ultimately uses the equals method. Given that you have a custom object (and not something like a String or int that have a defined equals), the simplest method would be to define an equals method for Contact that returns true if the two have the same phone number.

However, that might not be what you are looking for. For example, equals might need to check the name in other contexts.

There are a couple other approaches you could take. Since you mentioned Android, Java 8 streams are currently out. An Iterator loop might do the job. Collect all of the phone numbers for registered users into a Set (so you have the unique list), then start with a List of all of your contacts, and remove any that don't have a phone number from that set.

Set<String> registeredPhoneNumbers = new HashSet<>();
for (Contact c : registered_users) {
  registeredPhoneNumbers.add(c.getPhone());
}
List<Contact> common_contacts = new ArrayList<>(phone_contacts);
for (Iterator<Contact> iter = common_contacts.iterator(); iter.hasNext();) {
  Contact c = iter.next();
  if (!registeredPhoneNumbers.contains(c.getPhone())) {
    iter.remove();
  }
}

Since you mentioned in comments that there could be a million distinct registered_users, this might be more space-efficient:

Set<String> phoneNumbers = new HashSet<>();
for (Contact c : phone_contacts) {
    phoneNumbers.add(c.getPhone());
}

Set<String> overlappingNumbers = new HashSet<>();
for (Contact registered : registered_users) {
    if (phoneNumbers.contains(registered.getPhone())) {
        overlappingNumbers.add(registered.getPhone());
    }
}
List<Contact> common_contacts = new ArrayList<>();
for (Contact contact : phone_contacts) {
    if (overlappingNumbers.contains(contact.getPhone())) {
      common_contacts.add(contact);
    }
  }
}

You may want to check the phone number for null as well.

Sign up to request clarification or add additional context in comments.

4 Comments

What is c and iter in if loop? if (!registeredPhoneNumbers.contains(c.getPhone())) { iter.remove(); }
Thats what I get for writing an Iterator loop when all I do is Java 8 these days. Fixed.
It's working fine. Thanks! I just have 1 question. Is it efficient method if I have 1 million registered_users and hundreds of phone_contacts?
Depends on how you define efficient. Worst case, you have a million distinct phone numbers, so you will have a Set<String> of one million entries, which will take up quite a bit of memory (you did say Android...) The other option would be to build a Set of the unique phone numbers on phone contacts, which would be much smaller, then iterate over registered users, making note of which phone numbers are used - maybe store used ones in another Set. Finally, loop back over the phoneContacts, only keeping those that have a phone number that is being used.
0

Add these lines to your Contact class:

@Override
public boolean equals(Object obj) {
    return obj instanceof Contact &&
            this.name != null && this.name.equals(((Contact)obj).name) &&
            this.phone!= null && this.phone.equals(((Contact)obj).phone);
}

Ref: https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#equals-java.lang.Object-

See Also: hashCode()

Comments

0

If you use the method RetainAll in the List the you will get the common objects between 2 Lists..\

Example:

consider the lists of integers, (just for the sake of the example) it will work with your class...

public static void main(String[] args) {
    List<Integer> list1 = new ArrayList<Integer>(Arrays.asList(0, 1, 2, 3, 4, 5));
    List<Integer> list2 = new ArrayList<Integer>(Arrays.asList(1, 3, 5));
    List<Integer> list3 = new ArrayList<Integer>(list1);
    list3.retainAll(list2);
    System.out.println("List1:" + list1);
    System.out.println("List2:" + list2);
    System.out.println("List common:" + list3);

    }

In your case the class contacts needs to be modified so the Method ArrayLst.retainAll() can somehow identify whether a Contact is the same as the other using as criteria the Phone number...

Modify/Improve the Contact Class by adding the HashCode and Equals:

but you need to use as criteria only the phone Number

public class Contact {
    private String name;
    private int phone;

    public Contact(String name, int phone) {
    this.name = name;
    this.phone = phone;
    }

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }

    @Override
    public String toString() {
    return "Contact [name=" + name + ", phone=" + phone + "]";
    }

    @Override
    public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + phone;
    return result;
    }

    @Override
    public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Contact other = (Contact) obj;
    if (phone != other.phone)
        return false;
    return true;
    }

    public int getPhone() {
    return phone;
    }

    public void setPhone(int phone) {
    this.phone = phone;
    }
}

Implement the List of Contacts and call the method RetainAll

   public static void main(String[] args) {
    List<Contact> list1 = new ArrayList<Contact>(Arrays.asList(new Contact(UUID.randomUUID().toString(), 1),
        new Contact(UUID.randomUUID().toString(), 2), new Contact(UUID.randomUUID().toString(), 3),
        new Contact(UUID.randomUUID().toString(), 4), new Contact(UUID.randomUUID().toString(), 5)));
    List<Contact> list2 = new ArrayList<Contact>(Arrays.asList(new Contact(UUID.randomUUID().toString(), 1),
        new Contact(UUID.randomUUID().toString(), 3), new Contact(UUID.randomUUID().toString(), 5)));
    List<Contact> list3 = new ArrayList<Contact>(list1);
    list3.retainAll(list2);
    System.out.println("List1:" + list1);
    System.out.println("List2:" + list2);
    System.out.println("List common:" + list3);
    }

2 Comments

I need common phone only. Not entire object. Is there any way to modify that?
Tag says Android, so no.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.