首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在java流中映射groupingBy属性下的多个属性

如何在java流中映射groupingBy属性下的多个属性
EN

Stack Overflow用户
提问于 2021-06-10 17:54:46
回答 3查看 388关注 0票数 3

我试图获得每个学生的综合分数,按系分组,并按他们的综合分数分类。我就是这么做的。

学生班级属性:

代码语言:javascript
复制
private String firstName,lastName,branch,nationality,grade,shName;
private SubjectMarks subject;
private LocalDate dob;

SubjectMarks类:

代码语言:javascript
复制
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;
}

主修班:

代码语言:javascript
复制
    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())));

更新的代码:我就是这样得到输出的。

代码语言:javascript
复制
  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获得了所有分支中最高的聚合分数,欧洲经委会排在第一位,其次是其他分支和学生的汇总分数。

预期的结果是:列出学生的名字和他们的综合分数排序。

代码语言:javascript
复制
  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属性上的名称和平均值?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2021-06-11 09:07:25

输入:

代码语言:javascript
复制
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())
);

想法:

  1. group按“分支”
  2. 为每一组(列表)- sort按年级和map每个学生的地图“名称”,“年级”。

现在很容易编写代码:

代码语言:javascript
复制
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()))));

输出:

代码语言:javascript
复制
{
  A=[{Marry=87.0}, {John=77.0}],
  B=[{Arun=67.0}]
}

顺便问一下:

注意,在getAverageMarks中,浮点上下文中的整数除以整数。

代码语言:javascript
复制
public double getAverageMarks() {
    double avg = (getBiology() + getMaths() + getComputers())/3;
    return avg;
}

这将导致所有年级都采用这种格式- xx.0

如果是错误的,我建议采用这种方法:

代码语言:javascript
复制
public double getAverageMarks() {
    return DoubleStream.of(maths, biology, computers)
            .average()
            .getAsDouble();
}
票数 0
EN

Stack Overflow用户

发布于 2021-06-11 15:56:00

您最好选择返回类型为Map<String, Map<String, Double>>或具有适当equalshashCode的自定义类,以确保内部List<Custom>之间的唯一性。我将基于前者构建解决方案,您可以将其转换为更易读到实际代码的解决方案。

将每个branch特定的学生分组之后,要确保firstName映射到该学生的最大平均分数,您可以做的是使用toMap和基于Double::max.的合并执行一次缩减,然后根据标记(值)收集这些项。

下面的代码看起来可能有点复杂,但也可以分为几个步骤。

代码语言:javascript
复制
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)) 
            )));
票数 4
EN

Stack Overflow用户

发布于 2021-06-11 08:44:10

首先,在您的Map<String, List<Map<String,Double>>>中,列表中的映射将只包含一个键值对。所以我建议你把Map<String, List<Entry<String, Double>>>还给我。(Entry in java.util.Map)

另外,在学生班级中创建一个getAverageMarks,它将返回:

代码语言:javascript
复制
return subject.getAverageMarks();
代码语言:javascript
复制
// 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))));            
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67926249

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档