1

I have 2 lists and want to copy some element from one to another, i.e. there are old and new employees list I need to union 2 lists and delete the elements that include to the old list but not include in the new one.

I could solve the part of getting the union and intersection by using TreeSet and override the equals and hashcode functions of the Employees class....

Now, I want to exclude the elements that are in the old but not in the new and add them to the "deletedList"....which I got "ConcurrentModificationException"

I tried this instead of "iterator" but the same result: for(Employees e : employeesListDB)

Also I tried "CopyOnWriteArrayList" instead of "ArrayList" but no change!!

but the problem now that at the initialization of the empty list "deletedList" it is filled with multiple null elements before the add function!

Here is the code:

List<Employees> employeesListDB = this.findAll();     

Set<Employees> empSet = new TreeSet<Employees>(new EmployeeComparator());
empSet.addAll(employeesList);

List<Employees> deletedList = new ArrayList<Employees>();
Employees e = new Employees();

ListIterator<Employees> itr = employeesListDB.listIterator();    
for(itr.hasNext()) { 
  e = (Employees)itr.next();
  if(!empSet.contains(e)) {
    deletedList.add(e);
  }               
}

A counter Example:

The oldlist "employeesListDB" the employees list from the database:

[  
    {  
        "email":"mariam.moustafa@x.com"
    },
    {  
        "email":"sara.ahmed@x.com"
    },
    {  
        "email":"ali.hassan@x.com"
    },
    {  
        "email":"hoosen.imam-ally@x.com"
    },
    {  
        "email":"allan.randall@x.com"
    },
    {  
        "email":"nishaan.maharaj@x.com"
    }
]

The new list to be added:

[  
    {  
        "email":"ali.moustafa@x.com"
    },
    {  
        "email":"sara.ahmed@x.com"
    },
    {  
        "email":"emad.hamed@x.com"
    }  

]

The deleted list that I want:

[
{
"email":"mariam.moustafa@x.com" }, {
"email":"ali.hassan@x.com" }, {
"email":"hoosen.imam-ally@x.com" }, {
"email":"allan.randall@x.com" }, {
"email":"nishaan.maharaj@x.com" } ]

Sara mail will be updated...

Employee class has two fields {id,email} the new list (the list to be added to the db) is a list of only emails, id field are not recognized yet but the old list has the complete bean fields ...to compare between these 2 list I should override the Comparator to ignore the id field; Finding duplicates in a List ignoring a field

JUST I need to know, why when I use set.add operation, it adds the unique emails only! the original size of the list was 36 elements after adding it into a set it becomes only 16!!

 Set<Employees> oldSet = new TreeSet<Employees>(new EmployeeComparator());
        oldSet.addAll(employeesListDB);

        Set<Employees> newSet = new TreeSet<Employees>(new EmployeeComparator());
        newSet.addAll(employeesList);


        Set<Employees> deleted = Sets.difference(oldSet, newSet);
Community
  • 1
  • 1
Mariam A. Moustafa
  • 165
  • 1
  • 2
  • 14
  • I tried this instead of "iterator" but the same result: for(Employees e : employeesListDB) – Mariam A. Moustafa Jun 17 '15 at 09:13
  • Also I tried "CopyOnWriteArrayList" instead of "ArrayList" but no change!! – Mariam A. Moustafa Jun 17 '15 at 09:14
  • 2
    What is your question? – SamTebbs33 Jun 17 '15 at 09:15
  • Tip: You can edit your own question, so you might add the above comments to it instead of creating comments for them. – Christophe De Troyer Jun 17 '15 at 09:15
  • Your code looks fine - please post a complete example that reproduces your problem. – assylias Jun 17 '15 at 09:17
  • I am editing the question and will rewrite in clear way...it is urgent – Mariam A. Moustafa Jun 17 '15 at 09:19
  • It is very unclear...what are you trying, why are you trying and then so many why's. Does that help? – Rajesh Jun 17 '15 at 09:22
  • with your actual logic you add (max!) 1 item to `deleteList` . you need a loop `while(itr.hasNext)` instead of `if(itr.hasNext())` – griFlo Jun 17 '15 at 09:28
  • Please update your question with an example containing two lists, one new and one old, along with what the union you want to be. This will make it exponentially easier for us to help you. – Tim Biegeleisen Jun 17 '15 at 09:33
  • I think your whole question is unclear. Why do you need the TreeSet? just go through the oldList, check if the item is in the newList. if not, add it to the deleteList. – griFlo Jun 17 '15 at 09:42
  • I problem that Employee class has two fields {id,email} the new list (the list to be added to the db) is a list of only emails, id field are not recognized yet but the old list has the complete bean fields ...to compare between these 2 list I should override the Comparator to ignore the id field – Mariam A. Moustafa Jun 17 '15 at 09:46
  • @مريمقدالحياة and what should happen if 2 employess (different id) have the same email Adress (unlikely but its possible). And why is your newList (or Set or whatever) not a List or List but a List. if it has no id, it couldnt be a correct Employee – griFlo Jun 17 '15 at 09:54
  • good question, I already receive a list of emails as a String then I format them with JSON to be a list of Employees to compare a addedit/delete – Mariam A. Moustafa Jun 17 '15 at 09:59
  • 1
    but why don't you just go through the oldList, check if the email is present in the List of Emails (without converting it to an Employee) you can save if a email is found in an old employee. If it is not present in the List -> add the employee to the remove List. And at the end remove all emails which you saved during the loop from the newList. For every item which remains, create a new Employee – griFlo Jun 17 '15 at 10:04
  • Yes, I can check if the new email is already exist then no change but what is about an old email that is needed to remove and a new email that is needed to add... – Mariam A. Moustafa Jun 17 '15 at 10:08
  • 1
    @مريمقدالحياة see my last edit of my answer. this should work – griFlo Jun 17 '15 at 11:04
  • I am trying it right now :) – Mariam A. Moustafa Jun 17 '15 at 11:08

5 Answers5

2

As I understand, you need all elements that are contained by old set and not contained by new set.

For this purpose you can use Guava Sets#difference method:

Set<Employees> deleted = Sets.difference(oldSet, newSet);

Test with your data:

Set<String> oldEmployees = Sets.newHashSet("mariam.moustafa@x.com", "sara.ahmed@x.com", "ali.hassan@x.com", "hoosen.imam-ally@x.com", "allan.randall@x.com", "nishaan.maharaj@x.com");
Set<String> newEmployees = Sets.newHashSet("ali.moustafa@x.com", "sara.ahmed@x.com", "emad.hamed@x.com");

Set<String> diff = Sets.difference(oldEmployees, newEmployees);

System.out.println(diff);

Result:

[nishaan.maharaj@x.com, mariam.moustafa@x.com, ali.hassan@x.com, allan.randall@x.com, hoosen.imam-ally@x.com]
Denys Denysiuk
  • 775
  • 5
  • 11
  • A simple answer without a gazillion comments is exactly what this question needs right now. – Tim Biegeleisen Jun 17 '15 at 09:47
  • newSet may have new elements that are not already exist in the oldSet, SO i need to union then subtract the difference old-new – Mariam A. Moustafa Jun 17 '15 at 09:51
  • 1
    @مريمقدالحياة, new elements in new set will be ignored and will not pass to diff result, [Sets#difference](http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/Sets.html#difference(java.util.Set,%20java.util.Set)) – Denys Denysiuk Jun 17 '15 at 09:58
  • It works fine..but still I need to modify the algorithm...thanks in advance – Mariam A. Moustafa Jun 17 '15 at 10:04
  • JUST I need to know, why when I use set.add operation, it adds the unique emails only! the original size of the list was 36 elements after adding it into a set it becomes only 16!! Set oldSet = new TreeSet(new EmployeeComparator()); oldSet.addAll(employeesListDB); Set newSet = new TreeSet(new EmployeeComparator()); newSet.addAll(employeesList); Set deleted = Sets.difference(oldSet, newSet); – Mariam A. Moustafa Jun 17 '15 at 10:14
  • @مريمقدالحياة, [Set](http://docs.oracle.com/javase/7/docs/api/java/util/Set.html) - A collection that contains no duplicate elements... – Denys Denysiuk Jun 17 '15 at 10:31
  • I got this exception while I am trying the final code: ex = (java.util.ConcurrentModificationException) java.util.ConcurrentModificationException – Mariam A. Moustafa Jun 17 '15 at 12:03
  • Set deleted = Sets.difference(oldSet, newSet); Set added = Sets.difference(newSet, oldSet); try{ oldSet.removeAll(deleted); oldSet.addAll(added); }catch(Exception ex){ System.out.println(ex.getMessage()); } – Mariam A. Moustafa Jun 17 '15 at 12:05
  • First - read [THIS](http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/Sets.html#difference(java.util.Set,%20java.util.Set)) -- Returns an **unmodifiable** view of the difference of two sets. Second - update your question, your code is very strange – Denys Denysiuk Jun 17 '15 at 12:09
2

Here is a core Java solution using 2 simple steps:

[1] - Create a set setOld which contains the first set of emails
[2] - Subtract from setOld a new set of emails setNew

Set oldSet<String> = new HashSet<String>();  // original set of email addresses
oldSet.add("mariam.moustafa@x.com");
oldSet.add("sara.ahmed@x.com");
oldSet.add("ali.hassan@x.com");
oldSet.add("hoosen.imam-ally@x.com");
oldSet.add("allan.randall@x.com");
oldSet.add("nishaan.maharaj@x.com");

Set newSet<String> = new HashSet<String>();  // new set of email addresses
newSet.add("ali.moustafa@x.com");
newSet.add("sara.ahmed@x.com");
newSet.add("emad.hamed@x.com");

for (String s : newSet) {
    oldSet.remove(s);     // this will only remove the element if found
}

// display new contents of oldSet
for (String s : oldSet) {
    System.out.println(s);
}

Output:

mariam.moustafa@x.com
ali.hassan@x.com
hoosen.imam-ally@x.com
allan.randall@x.com
nishaan.maharaj@x.com
Tim Biegeleisen
  • 502,043
  • 27
  • 286
  • 360
  • It works fine..but still I need to modify the algorithm...thanks in advance – Mariam A. Moustafa Jun 17 '15 at 10:05
  • JUST I need to know, why when I use set.add operation, it adds the unique emails only! the original size of the list was 36 elements after adding it into a set it becomes only 16!! Set oldSet = new TreeSet(new EmployeeComparator()); oldSet.addAll(employeesListDB); Set newSet = new TreeSet(new EmployeeComparator()); newSet.addAll(employeesList); Set deleted = Sets.difference(oldSet, newSet); – Mariam A. Moustafa Jun 17 '15 at 10:16
  • Yes, a `Set` cannot, by definition, have duplicates. – Tim Biegeleisen Jun 17 '15 at 10:36
1

the empty list filled with multiple null elements before the add function!

This is becuase you're using the ArrayList which contains the following constant:

private static final int DEFAULT_CAPACITY = 10;

Which mean when you create the ArrayList<T> with the new operator you actually create an Array of T which contains 10 nulls (It's contained as private transient Object[] elementData field).

The JLS said:

Every variable in a program must have a value before its value is used:

Each class variable, instance variable, or array component is initialized with a default value when it is created (§15.9, §15.10.2):

[...]

For all reference types (§4.3), the default value is null.

1

Try it this way (Made a small TestCase):

private static Employee createEmployee(String string) {
    Employee employee = new Employee();
    employee.setEmail(string);
    return employee;
}

public static void main(String[] args)  {

    List<String> newMails = new ArrayList<>();
    List<Employee> oldList = new ArrayList<>();

    oldList.add(createEmployee("mariam.moustafa@x.com"));
    oldList.add(createEmployee("sara.ahmed@x.com"));
    oldList.add(createEmployee("ali.hassan@x.com"));
    oldList.add(createEmployee("hoosen.imam-ally@x.com"));
    oldList.add(createEmployee("allan.randall@x.com"));
    oldList.add(createEmployee("nishaan.maharaj@x.com"));

    newMails.add("ali.moustafa@x.com");
    newMails.add("sara.ahmed@x.com");
    newMails.add("emad.hamed@x.com");

    List<Employee> delete = new ArrayList<>();
    Set<String> removedMails = new HashSet<>();

    for (Employee emp : oldList) {
        if (!newMails.contains(emp.getEmail())) {
            delete.add(emp);
        }
        removedMails.add(emp.getEmail());
    }
    newMails.removeAll(removedMails);
    // remove emploeyees in delete
    oldList.removeAll(delete);

    // Create employee for left MAils
    for (String newMail : newMails) {
        oldList.add(createEmployee(newMail));
    }

    //Old and new Employees
    for (Employee emp : oldList) {
        System.out.println(emp.getEmail());
    }

}

simple Employee class:

class Employee {
String email;

public String getEmail() {
    return email;
}

public void setEmail(String email) {
    this.email = email;
}

}

output:

sara.ahmed@x.com
ali.moustafa@x.com
emad.hamed@x.com
griFlo
  • 2,084
  • 18
  • 28
1

Use List removeAll method. You will need to override equals method in your Employees class. PFB sample snippet based on employee id, you will need to modify it to fit based on email id:

import java.util.*;

public class StringArray {

    public static void main(String args[]) {

        List<Employee> oldList = new ArrayList<Employee>();
        oldList.add(new Employee(1));
        oldList.add(new Employee(2));
        oldList.add(new Employee(3));
        oldList.add(new Employee(4));

        List<Employee> newList = new ArrayList<Employee>();
        newList.add(new Employee(3));
        newList.add(new Employee(4));
        newList.add(new Employee(5));
        newList.add(new Employee(6));

        oldList.removeAll(newList);

        System.out.println("Printing delete list");
        for (Employee employee : oldList)
            System.out.println(employee);

        System.out.println("Printing updated list");
        for (Employee employee : newList)
            System.out.println(employee);
    }
}

public class Employee {
    private int id; 

    public Employee(int id) {
        super();
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "Employee [id=" + this.id + "]";
    }

    @Override
    public boolean equals(Object o) {       

        if (o == this)
            return true;        

        if (!(o instanceof Employee)) 
            return false; 

        Employee c = (Employee) o;         

        return this.id == c.id;     
    }   
}
Rajesh
  • 2,135
  • 1
  • 12
  • 14