I was trying to filter a list based on multiple conditions, sorting.
class Student{
private int Age;
private String className;
privat
Use the toMap collector:
Collection values = students.stream()
.collect(toMap(Student::getName,
Function.identity(),
BinaryOperator.maxBy(Comparator.comparingInt(Student::getAge))))
.values();
Explanation
We're using this overload of toMap:
toMap(Function super T,? extends K> keyMapper,
Function super T,? extends U> valueMapper,
BinaryOperator mergeFunction)
Student::getName above is the keyMapper function used to extract the values for the map keys.Function.identity() above is the valueMapper function used to extract the values for the map values where Function.identity() simply returns the elements in the source them selves i.e. the Student objects.BinaryOperator.maxBy(Comparator.comparingInt(Student::getAge)) above is the merge function used to "decide which Student object to return in the case of a key collission i.e. when two given students have the same name" in this case taking the oldest Student .values() returns us a collection of students.The equivalent C# code being:
var values = students.GroupBy(s => s.Name, v => v,
(a, b) => b.OrderByDescending(e => e.Age).Take(1))
.SelectMany(x => x);
Explanation (for those unfamiliar with .NET)
We're using this extension method of GroupBy:
System.Collections.Generic.IEnumerable GroupBy
(this System.Collections.Generic.IEnumerable source,
Func keySelector,
Func elementSelector,
Func,TResult> resultSelector);
s => s.Name above is the keySelector function used to extract the value to group by.v => v above is the elementSelector function used to extract the values i.e. the Student objects them selves.b.OrderByDescending(e => e.Age).Take(1) above is the resultSelector which given an IEnumerable represented as b takes the oldest student..SelectMany(x => x); to collapse the resulting IEnumerable> into a IEnumerable.