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)));
Here we will see how to get common elements from two lists we can even say the intersection of two lists using different ways. retainAll () method from the Collection interface is used to remove the common elements from two different lists. We even get the common elements from two lists using java 8 stream API distinct () method.
The intersection should contain each common element only once. The order shouldn't matter, thus toSet is the most straightforward choice, but we can also use toList or another collector method.
Like many other things, this has become much easier thanks to the introduction of streams in Java 8. 2. Intersection of Two Lists of Strings Let's create two List s of String s with some intersection — both having some duplicated elements:
Then two instances are equal only if they refer to exactly the same object on the heap. For more information about the equals method, see our article on Java equals () and hashCode () Contracts. 4. Conclusion
Can some tell me what am I doing wrong?
You violate the Side-effects principle of java-stream 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());
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))
))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With