我试图根据多种条件对列表进行排序。
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;
}
}
现在,如果我有清单,说
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"));
我如何能够获得一个名字不同的最老的学生的名单? 在C#中,使用System.Linq Group会非常简单,然后比较并使用select进行展平,我不太确定如何在Java中实现相同的目标。
答案 0 :(得分:18)
使用toMap
收集器:
Collection<Student> values = students.stream()
.collect(toMap(Student::getName,
Function.identity(),
BinaryOperator.maxBy(Comparator.comparingInt(Student::getAge))))
.values();
说明
我们正在使用toMap
的重载:
toMap(Function<? super T,? extends K> keyMapper,
Function<? super T,? extends U> valueMapper,
BinaryOperator<U> mergeFunction)
Student::getName
是keyMapper
函数,用于提取地图键的值。Function.identity()
是一种valueMapper
函数,用于提取映射值的值,其中Function.identity()
只是返回源中它们自己的元素,即Student
对象。 BinaryOperator.maxBy(Comparator.comparingInt(Student::getAge))
是合并函数,用于“在键冲突的情况下(即两个给定的学生具有相同的名称时)确定要返回哪个Student对象”,在这种情况下采用最早的Student
。values()
会向我们返回一组学生。等效的C#代码为:
var values = students.GroupBy(s => s.Name, v => v,
(a, b) => b.OrderByDescending(e => e.Age).Take(1))
.SelectMany(x => x);
说明(适用于不熟悉.NET的用户)
我们正在使用GroupBy
的扩展方法:
System.Collections.Generic.IEnumerable<TResult> GroupBy<TSource,TKey,TElement,TResult>
(this System.Collections.Generic.IEnumerable<TSource> source,
Func<TSource,TKey> keySelector,
Func<TSource,TElement> elementSelector,
Func<TKey,System.Collections.Generic.IEnumerable<TElement>,TResult> resultSelector);
s => s.Name
是keySelector
函数,用于提取要分组的值。v => v
是elementSelector
函数,用于提取值,即Student
对象本身。b.OrderByDescending(e => e.Age).Take(1)
是resultSelector
,其中给定为IEnumerable<Student>
的{{1}}接受了年龄最大的学生。b
将生成的.SelectMany(x => x);
折叠成IEnumerable<IEnumerable<Student>>
。答案 1 :(得分:7)
或者没有流:
Map<String, Student> map = new HashMap<>();
students.forEach(x -> map.merge(x.getName(), x, (oldV, newV) -> oldV.getAge() > newV.getAge() ? oldV : newV));
Collection<Student> max = map.values();
答案 2 :(得分:2)
如果您只需要对分组进行排序,则非常简单:
array['']
收集中的输出:
答案 3 :(得分:1)
只需混合和合并其他解决方案,您也可以执行以下操作:
Map<String, Student> nameToStudentMap = new HashMap<>();
Set<Student> finalListOfStudents = students.stream()
.map(x -> nameToStudentMap.merge(x.getName(), x, (a, b) -> a.getAge() > b.getAge() ? a : b))
.collect(Collectors.toSet());