I was trying to filter a list based on multiple conditions, sorting.
class Student{
private int Age;
private String className;
private String Name;
public Student(int age, String className, String name) {
Age = age;
this.className = className;
Name = name;
}
public int getAge() {
return Age;
}
public void setAge(int age) {
Age = age;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
}
Now if I have a list of that, say
List<Student> students = new ArrayList<>();
students.add(new Student(24, "A", "Smith"));
students.add(new Student(24, "A", "John"));
students.add(new Student(30, "A", "John"));
students.add(new Student(20, "B", "John"));
students.add(new Student(24, "B", "Prince"));
How would I be able to get a list of the oldest students with a distinct name? In C# this would be quite simple by using System.Linq GroupBy then comparing and then flattening with select, I'm not too sure how I could achieve the same in Java.
Use the
toMap
collector:Explanation
We're using this overload of
toMap
:Student::getName
above is thekeyMapper
function used to extract the values for the map keys.Function.identity()
above is thevalueMapper
function used to extract the values for the map values whereFunction.identity()
simply returns the elements in the source them selves i.e. theStudent
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 oldestStudent
.values()
returns us a collection of students.The equivalent C# code being:
Explanation (for those unfamiliar with .NET)
We're using this extension method of
GroupBy
:s => s.Name
above is thekeySelector
function used to extract the value to group by.v => v
above is theelementSelector
function used to extract the values i.e. theStudent
objects them selves.b.OrderByDescending(e => e.Age).Take(1)
above is theresultSelector
which given anIEnumerable<Student>
represented asb
takes the oldest student..SelectMany(x => x);
to collapse the resultingIEnumerable<IEnumerable<Student>>
into aIEnumerable<Student>
.If you need a grouping only sorted, it is quite simple:
Output in collect:
Just to mix and merge the other solutions, you could alternatively do :
Or without streams: