5

An intersection of Two Lists Objects in java 8. Can some tell me what am I doing wrong?

List<Student> originalStudent = new ArrayList<>();
List<Student> newStudent = new ArrayList<>();

List<Student> intersectListStudent = new LinkedList<>()

originalStudent.add(new Student("William", "Tyndale",1));
originalStudent.add(new Student("Jonathan", "Edwards",2));
originalStudent.add(new Student("Martin", "Luther"),3);

newStudent.add(new Student("Jonathan", "Edwards",2));
newStudent.add(new Student("James", "Tyndale",4));
newStudent.add(new Student("Roger", "Moore",5));


originalStudent.forEach(n ->
        newStudent.stream()
                .filter(db -> !n.getName().equals(db.getName()) &&
                        !n.getLastName().equals(db.getLastName()))
                    .forEach(student-> intersectListStudent .add(student)));
2
  • 2
    what is the output that you're expecting? what is that you think is wrong? that's not self explanatory by the way Commented Dec 16, 2018 at 18:04
  • 2
    Since a List can contain the same element multiple times, when you intersect the lists, if A has element x three times, and B has element x twice times, how many times do you expect the answer in the final list? 3? 2? 1? This will determine which of these approaches works. Commented Dec 16, 2018 at 21:30

2 Answers 2

15

Can some tell me what am I doing wrong?

You violate the Side-effects principle of which in a nutshell says that a stream shouldn't modify another collection while performing the actions through the pipelines. I haven't tested your code, however, this is not a way you should treat streams.


How to do it better?

Simply use the List::contains in the filter's predicate to get rid of the unique values.

List<Student> students = originalStudent.stream()
                                        .filter(newStudent::contains)
                                        .collect(Collectors.toList());

This solution (understand the method List::contains) is based on the implemented equality comparison using Object::equals. Hence, there is needed to override the very same method in the class Student.

Edit: Please, be aware that that automatically overriding the Object::equals will mind the id to the equality computation. Therefore the equality will be based on the name and surname only. (thanks to @nullpointer).

Without the Object::equals overridden?

You have to perform the comparison in the filter using another stream and the method Stream::anyMatch which returns true if the predicate is qualified.

List<Student> students = originalStudent.stream()
              .filter(os -> newStudent.stream()                    // filter
                  .anyMatch(ns ->                                  // compare both
                       os.getName().equals(ns.getName() &&         // name
                       os.getLastName().equals(ns.getLastName()))) // last name
              .collect(Collectors.toList());
Sign up to request clarification or add additional context in comments.

4 Comments

this would definitely need an object comparison. also the fact that is the last attribute value changes in the two sample lists provided, the output would vary here from what is expected in the question.
I meant, if I change originalStudent.add(new Student("Jonathan", "Edwards",2)); to originalStudent.add(new Student("Jonathan", "Edwards",7));, you first code block wouldn't provide same output as your latter suggestion.
Plus one for the solution with anyMatch and collect :)
@Myjay1516, why is this not the accepted answer? :/
1

What you can do is construct a SortedSet<Student> from the two concatenated lists originalStudent and newStudent. The sorted set uses a Comparator.comparing(Student::getName).thenComparing(Student::getLastName) as its comparator.

Stream.concat(originalStudent.stream(), newStudent.stream())
    .collect(Collectors.toCollection(() -> new TreeSet<>(
        Comparator.comparing(Student::getFname)
            .thenComparing(Student::getLname))
    ))

1 Comment

Works fine for me. Thank you!... Those who are working with list you have to convert treeset to list. new ArrayList<Student>(treeSetListVariable)

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.