3

I have two Lists containing objects of this class:

public class ClassObj {
    private Integer Id;
    private List<String> students;
}

I want to compare the objects in those two lists by students. I have to compare the lists and get data lijke below

  1. I need to create a new List containing those ClassObj objects which are present in list1 but not in list2
  2. I need to create a new List containing those ClassObj objects which are present in list2 but not in list1
  3. I need to create a new List containing those ClassObj objects which are present in both the lists using java8 streams

I tried with the below code

List<ClassObj> prevYearList = getPrevYearData(id);
List<ClassObj> currYearList = getCurrentYearData(id);

To find students who got TC (exists in list 1 but not in list2)

List<ClassObj> studentsGotTC = prevYearList.stream()
                    .filter(curr -> (currYearList.stream().filter(prev -> prev.getStudents().equals(curr.getStudents()))
                            .count()) < 1)
                    .collect(Collectors.toList());

To find new Admission (exists in list2 but not in list1)

List<ClassObj> newAdmission = currYearList.stream()
                    .filter(prev -> (prevYearList.stream()
                            .filter(curr -> prev.getStudents().equals(curr.getStudents())).count()) < 1)
                    .collect(Collectors.toList());

To find Students continuing in the school (exists in both list)

List<List<String>> studentsList = studentsGotTC.parallelStream()
                    .map(ClassObj::getStudents)
                    .collect(Collectors.toList());
List<ClassObj> existingStudents = prevYearList.stream()
                    .filter(e -> !studentsList.contains(e.getStudents()))
                    .collect(Collectors.toList());

It is returning me the results properly but i dont want to go through two streams and filter data, how to optimize the above code efficiently. i.e., by using single stream

ernest_k
  • 44,416
  • 5
  • 53
  • 99
krishna
  • 343
  • 2
  • 5
  • 19
  • One stream doing one thing is the right way. Going through the stream three times might feel expensive but it isn't. What's most expensive in your example is most likely the use of paralell streams since the overhead will exceed the gains for Lists with less than about 15000 items. – Nicktar Jan 30 '20 at 05:08

2 Answers2

1

You might not really need Streams at all for the task. How about this -

Set<ClassObj> uniqueStudentsOfPrevYear = new HashSet<>(prevYearList);
Set<ClassObj> uniqueStudentsOfCurrYear = new HashSet<>(currYearList);

List<ClassObj> studentsWithTC = new ArrayList<>(prevYearList);
studentsWithTC.removeIf(uniqueStudentsOfCurrYear::contains);

List<ClassObj> newAdmissions = new ArrayList<>(currYearList);
newAdmissions.removeIf(uniqueStudentsOfPrevYear::contains);

List<ClassObj> overlapping = new ArrayList<>(currYearList);
overlapping.retainAll(uniqueStudentsOfPrevYear);
Naman
  • 27,789
  • 26
  • 218
  • 353
0

For part 3 Common elements from both the List

Set<String> result = list.stream()
  .distinct()
  .filter(otherList::contains)
  .collect(Collectors.toSet());

After that, you can change the Set into a List.

For Part 1 And 2, you need to override the equals and hashcode method in ClassObj. So, you can use contains methods of the list. ArrayList's custom Contains method

List<ClassObj> studentsGotTC = prevYearList.stream()
                    .filter(prevYear-> currList.contains(prevYear))
                    .collect(Collectors.toList());
Harsh Mishra
  • 1,975
  • 12
  • 15