如何在 java 流中映射 groupingBy 属性 下的多个属性
How to map multiple properties under groupingBy property in java streams
我正在尝试获取按部门分组并按其总分排序的每个学生的总分。
这就是我正在尝试的方式。
学生class属性:
private String firstName,lastName,branch,nationality,grade,shName;
private SubjectMarks subject;
private LocalDate dob;
主题标记 class:
public SubjectMarks(int maths, int biology, int computers) {
this.maths = maths;
this.biology = biology;
this.computers = computers;
}
public double getAverageMarks() {
double avg = (getBiology() + getMaths() + getComputers())/3;
return avg;
}
主要class:
Collections.sort(stList, new Comparator<Student>() {
@Override
public int compare(Student m1, Student m2) {
if(m1.getSubject().getAverageMarks() == m2.getSubject().getAverageMarks()){
return 0;
}
return m1.getSubject().getAverageMarks()< m2.getSubject().getAverageMarks()? 1 : -1;
}
});
Map<String, List<Student>> groupSt=stList.stream().collect(Collectors.groupingBy(Student::getBranch,
LinkedHashMap::new,Collectors.toList()));
groupSt.forEach((k, v) -> System.out.println("\nBranch Name: " + k + "\n" + v.stream()
.flatMap(stud->Stream.of(stud.getFirstName(),stud.getSubject().getAverageMarks())).collect(Collectors.toList())));
更新代码:这就是我获取输出的方式。
Branch Name: ECE
[Bob, 96.0, TOM, 84.33333333333333]
Branch Name: CSE
[Karthik, 94.33333333333333, Angelina, 91.0, Arun, 80.66666666666667]
Branch Name: EEE
[Meghan, 85.0]
这是实际的排序顺序,但 Student 对象在用逗号 (,) 分隔的一行中变平。
在上面的输出中,由于 Bob 获得了所有分支的最高总分,因此 ECE 排在第一位,然后是其他分支,以学生总分排序。
预期结果是:
已排序的学生姓名列表。
Branch Name: ECE
[{Bob, 96.0},{TOM, 84.33333333333333}]
Branch Name: CSE
[{Karthik, 94.33333333333333}, {Angelina, 91.0}, {Arun,
80.66666666666667}]
Branch Name: EEE
[Meghan, 85.0]
有什么方法可以使用流在 groupingBy
a 属性 上同时映射名称和平均值?
首先,在您的 Map<String, List<Map<String,Double>>>
中,列表中的地图将只包含一个键值对。所以我建议你 return Map<String, List<Entry<String, Double>>>
。 (Entry
在 java.util.Map
中)
此外,在您的学生 class 中创建一个 getAverageMarks
,它将 return:
return subject.getAverageMarks();
// First define a function to sort based on average marks
UnaryOperator<List<Entry<String, Double>>> sort =
list -> {
Collections.sort(list, Collections.reverseOrder(Entry.comparingByValue()));
return list;
};
// function to create entry
Function<Student, Entry<String, Double>> getEntry =
s -> Map.entry(s.getFirstName(), s.getAverageMarks());
// return this
list.stream()
.collect(Collectors.groupingBy(
Student::getBranch,
Collectors.mapping(getEntry, // map each student
// collect and apply sort as finisher
Collector.of(ArrayList::new,
List::add,
(x,y) -> {x.addAll(y); return x;},
sort))));
输入:
List<Student> stList = Arrays.asList(
new Student("John", "Wall", "A", "a", "C", "sa", new SubjectMarks(65, 67, 100), LocalDate.now()),
new Student("Arun", "Wall", "B", "a", "C", "sa", new SubjectMarks(45, 61, 95), LocalDate.now()),
new Student("Marry", "Wall", "A", "a", "C", "sa", new SubjectMarks(90, 80, 92), LocalDate.now())
);
想法:
group
按“分支”
- 对于每个组(列表)-
sort
按年级和 map
每个学生到“姓名”,“年级”的地图。
现在编码很容易了:
Map<String, List<Map<String, Double>>> branchToSortedStudentsByGrade = stList.stream().collect(Collectors.groupingBy(
Student::getBranch, Collectors.collectingAndThen(Collectors.toList(),
l -> l.stream()
.sorted(Comparator.comparing(st -> st.getSubject().getAverageMarks(), Comparator.reverseOrder()))
.map(student -> Collections.singletonMap(student.getFirstName(), student.getSubject().getAverageMarks()))
.collect(Collectors.toList()))));
输出:
{
A=[{Marry=87.0}, {John=77.0}],
B=[{Arun=67.0}]
}
顺便说一句:
请注意,您在 getAverageMarks
:
中的浮点上下文中除以整数
public double getAverageMarks() {
double avg = (getBiology() + getMaths() + getComputers())/3;
return avg;
}
这将导致所有成绩都采用这种格式- xx.0
如果是误操作,我会推荐这种方法:
public double getAverageMarks() {
return DoubleStream.of(maths, biology, computers)
.average()
.getAsDouble();
}
您宁愿选择 return 类型作为 Map<String, Map<String, Double>>
或具有适当 equals
和 hashCode
的自定义 class 以确保内部 List<Custom>
的唯一性。我会根据前者构建解决方案,您可以将其转换为对您的实际代码更具可读性的解决方案。
一旦您对每个 branch
个特定学生进行了分组,您可以做些什么来确保 firstName 映射到该学生的最大平均分数 是执行减少使用toMap
合并基于 Double::max
... 然后 根据标记(值)收集这些条目。
以下代码可能看起来有点复杂,但也可以分解为多个步骤。
Map<String, LinkedHashMap<String, Double>> branchStudentsSortedOnMarks = stList.stream()
.collect(Collectors.groupingBy(Student::getBranch, // you got it!
Collectors.collectingAndThen(
Collectors.toMap(Student::getFirstName,
s -> s.getSubject().getAverageMarks(), Double::max), // max average marks per name
map -> map.entrySet().stream()
.sorted(Map.Entry.<String, Double>comparingByValue().reversed()) // sorted inn reverse based on value
.collect(Collectors.toMap(Map.Entry::getKey,
Map.Entry::getValue, (a, b) -> b, LinkedHashMap::new))
)));
我正在尝试获取按部门分组并按其总分排序的每个学生的总分。 这就是我正在尝试的方式。
学生class属性:
private String firstName,lastName,branch,nationality,grade,shName;
private SubjectMarks subject;
private LocalDate dob;
主题标记 class:
public SubjectMarks(int maths, int biology, int computers) {
this.maths = maths;
this.biology = biology;
this.computers = computers;
}
public double getAverageMarks() {
double avg = (getBiology() + getMaths() + getComputers())/3;
return avg;
}
主要class:
Collections.sort(stList, new Comparator<Student>() {
@Override
public int compare(Student m1, Student m2) {
if(m1.getSubject().getAverageMarks() == m2.getSubject().getAverageMarks()){
return 0;
}
return m1.getSubject().getAverageMarks()< m2.getSubject().getAverageMarks()? 1 : -1;
}
});
Map<String, List<Student>> groupSt=stList.stream().collect(Collectors.groupingBy(Student::getBranch,
LinkedHashMap::new,Collectors.toList()));
groupSt.forEach((k, v) -> System.out.println("\nBranch Name: " + k + "\n" + v.stream()
.flatMap(stud->Stream.of(stud.getFirstName(),stud.getSubject().getAverageMarks())).collect(Collectors.toList())));
更新代码:这就是我获取输出的方式。
Branch Name: ECE
[Bob, 96.0, TOM, 84.33333333333333]
Branch Name: CSE
[Karthik, 94.33333333333333, Angelina, 91.0, Arun, 80.66666666666667]
Branch Name: EEE
[Meghan, 85.0]
这是实际的排序顺序,但 Student 对象在用逗号 (,) 分隔的一行中变平。
在上面的输出中,由于 Bob 获得了所有分支的最高总分,因此 ECE 排在第一位,然后是其他分支,以学生总分排序。
预期结果是: 已排序的学生姓名列表。
Branch Name: ECE
[{Bob, 96.0},{TOM, 84.33333333333333}]
Branch Name: CSE
[{Karthik, 94.33333333333333}, {Angelina, 91.0}, {Arun,
80.66666666666667}]
Branch Name: EEE
[Meghan, 85.0]
有什么方法可以使用流在 groupingBy
a 属性 上同时映射名称和平均值?
首先,在您的 Map<String, List<Map<String,Double>>>
中,列表中的地图将只包含一个键值对。所以我建议你 return Map<String, List<Entry<String, Double>>>
。 (Entry
在 java.util.Map
中)
此外,在您的学生 class 中创建一个 getAverageMarks
,它将 return:
return subject.getAverageMarks();
// First define a function to sort based on average marks
UnaryOperator<List<Entry<String, Double>>> sort =
list -> {
Collections.sort(list, Collections.reverseOrder(Entry.comparingByValue()));
return list;
};
// function to create entry
Function<Student, Entry<String, Double>> getEntry =
s -> Map.entry(s.getFirstName(), s.getAverageMarks());
// return this
list.stream()
.collect(Collectors.groupingBy(
Student::getBranch,
Collectors.mapping(getEntry, // map each student
// collect and apply sort as finisher
Collector.of(ArrayList::new,
List::add,
(x,y) -> {x.addAll(y); return x;},
sort))));
输入:
List<Student> stList = Arrays.asList(
new Student("John", "Wall", "A", "a", "C", "sa", new SubjectMarks(65, 67, 100), LocalDate.now()),
new Student("Arun", "Wall", "B", "a", "C", "sa", new SubjectMarks(45, 61, 95), LocalDate.now()),
new Student("Marry", "Wall", "A", "a", "C", "sa", new SubjectMarks(90, 80, 92), LocalDate.now())
);
想法:
group
按“分支”- 对于每个组(列表)-
sort
按年级和map
每个学生到“姓名”,“年级”的地图。
现在编码很容易了:
Map<String, List<Map<String, Double>>> branchToSortedStudentsByGrade = stList.stream().collect(Collectors.groupingBy(
Student::getBranch, Collectors.collectingAndThen(Collectors.toList(),
l -> l.stream()
.sorted(Comparator.comparing(st -> st.getSubject().getAverageMarks(), Comparator.reverseOrder()))
.map(student -> Collections.singletonMap(student.getFirstName(), student.getSubject().getAverageMarks()))
.collect(Collectors.toList()))));
输出:
{
A=[{Marry=87.0}, {John=77.0}],
B=[{Arun=67.0}]
}
顺便说一句:
请注意,您在 getAverageMarks
:
public double getAverageMarks() {
double avg = (getBiology() + getMaths() + getComputers())/3;
return avg;
}
这将导致所有成绩都采用这种格式- xx.0
如果是误操作,我会推荐这种方法:
public double getAverageMarks() {
return DoubleStream.of(maths, biology, computers)
.average()
.getAsDouble();
}
您宁愿选择 return 类型作为 Map<String, Map<String, Double>>
或具有适当 equals
和 hashCode
的自定义 class 以确保内部 List<Custom>
的唯一性。我会根据前者构建解决方案,您可以将其转换为对您的实际代码更具可读性的解决方案。
一旦您对每个 branch
个特定学生进行了分组,您可以做些什么来确保 firstName 映射到该学生的最大平均分数 是执行减少使用toMap
合并基于 Double::max
... 然后 根据标记(值)收集这些条目。
以下代码可能看起来有点复杂,但也可以分解为多个步骤。
Map<String, LinkedHashMap<String, Double>> branchStudentsSortedOnMarks = stList.stream()
.collect(Collectors.groupingBy(Student::getBranch, // you got it!
Collectors.collectingAndThen(
Collectors.toMap(Student::getFirstName,
s -> s.getSubject().getAverageMarks(), Double::max), // max average marks per name
map -> map.entrySet().stream()
.sorted(Map.Entry.<String, Double>comparingByValue().reversed()) // sorted inn reverse based on value
.collect(Collectors.toMap(Map.Entry::getKey,
Map.Entry::getValue, (a, b) -> b, LinkedHashMap::new))
)));