How can I remove list of objects (list1) comparing another list of Objects(list2) by id and add removed object from list1 into another list (list3) using java 8
Example :
List<Employee> list1 = Stream.of(
new Employee("100","Boston","Massachusetts"),
new Employee("400","Atlanta","Georgia"),
new Employee("300","pleasanton","California"),
new Employee("200","Decatur","Texas"),
new Employee("500","Cumming","Atlanta"),
new Employee("98","sula","Maine"),
new Employee("156","Duluth","Ohio"))
.collect(Collectors.toList());
From the above list need to remove employee object based on id of below list.
List<Employee> list2 = Stream.of(
new Employee("100","Boston","Massachusetts"),
new Employee("800","pleasanton","California"),
new Employee("400","Atlanta","Georgia"),
new Employee("10","Decatur","Texas"),
new Employee("500","Cumming","Atlanta"),
new Employee("50","sula","Maine"),
new Employee("156","Duluth","Ohio"))
.collect(Collectors.toList());
Expected Output : list1 and list3
List<Employee> list1 = Stream.of(
new Employee("100","Boston","Massachusetts"),
new Employee("400","Atlanta","Georgia"),
new Employee("500","Cumming","Atlanta"),
new Employee("156","Duluth","Ohio"))
.collect(Collectors.toList());
List<Employee> list3 = Stream.of(
new Employee("300","pleasanton","California"),
new Employee("200","Decatur","Texas"),
new Employee("98","sula","Maine")
)
.collect(Collectors.toList());
Tried below way but not working as expected
List<Employee> list3 = new ArrayList<>();
if(CollectionUtils.isNotEmpty(list1) && CollectionUtils.isNotEmpty(list2)){
list2.stream().forEachOrdered( l2 -> {
Optional<Employee> nonMatch = list1.stream().filter(l1 -> !l1.getId().equalsIgnoreCase(l2.getId())).findAny();
if(nonMatch.isPresent()){
list3.add(nonMatch.get());
list1.removeIf(l1 -> l1.getId().equalsIgnoreCase(nonMatch.get().getId()));
}
});
}
System.out.println(list1);
System.out.println(list3);
CodePudding user response:
Here come two possible solutions.
This one is short and concise, but does in fact not remove elements from list1
but utilizes a partitioning collector to create the two lists. Think of the partitioning collector as kind of a two-way filter: if your predicate is fulfilled, collect to one list, if it's not, collect to the other list. The predicate in our case actually is "does list2 contain an employee with the same ID as the stream element from list1?". In order to lower the actual overhead, the code prepares a list of IDs from list2
up-front.
final List<String> list2Ids = list2.stream()
.map(Employee::getId)
.collect(Collectors.toList());
Map<Boolean, List<Employee>> partitioned = list1.stream()
.collect(Collectors.partitioningBy(e -> list2Ids.contains(e.getId())));
list1 = partitioned.get(true);
List<Employee> list3 = partitioned.get(false);
If you need to keep list1
- e.g. for memory foot-print reasons - and really have to remove the elements from it, I'd say you will have to stick to the really old-fashioned iterator. The reason for that is that iterators allow you to iterate some collection and remove elements while doing so. The next sample does exactly this. Note, that I prepared a list of IDs of list2
up-front again.
final List<String> list2Ids = list2.stream()
.map(Employee::getId)
.collect(Collectors.toList());
final List<Employee> list3 = new LinkedList<>();
for (Iterator<Employee> iterator = list1.iterator(); iterator.hasNext();) {
Employee next = iterator.next();
if (!list2Ids.contains(next.getId())) {
list3.add(next);
iterator.remove();
}
}
CodePudding user response:
You can address this problem in the following steps (time complexity of each step is linear):
- create a
Set
ofid
contained in thelist2
; - generate the list of
Employee
(denoted asnonCommonId
in the code) from thelist1
that have no commonid
withEmployee
contained in thelist2
by checking everyid
from thelist1
against theSet
obtained at the previous step. - apply
removeAll()
on the listid
discard all the employee that are present in the list obtained at the previous step.
The overall time complexity O(n m).
Set<String> idSet = list2.stream()
.map(Employee::id)
.collect(Collectors.toSet());
List<Employee> nonCommonId = list1.stream()
.filter(emp -> idSet.contains(emp.id()))
.collect(Collectors.toList());
list1.removeAll(new HashSet<>(nonCommonId));
// diplaying results
System.out.println("List1:");
list1.forEach(System.out::println);
System.out.println("nonCommonId:");
nonCommonId.forEach(System.out::println);
Output:
List1:
Employee[id=100, city=Boston, state=Massachusetts]
Employee[id=400, city=Atlanta, state=Georgia]
Employee[id=500, city=Cumming, state=Atlanta]
Employee[id=156, city=Duluth, state=Ohio]
nonCommonId:
Employee[id=300, city=pleasanton, state=California]
Employee[id=200, city=Decatur, state=Texas]
Employee[id=98, city=sula, state=Maine]