【问题标题】:Group list of object by an attribute and set other remaining attribute to different object list : Java 8 stream and Lambdas按属性对对象列表进行分组,并将其他剩余属性设置为不同的对象列表:Java 8 流和 Lambda
【发布时间】:2018-08-01 04:18:20
【问题描述】:

对 Java8 流/Lambda 非常陌生。我需要使用属性(Id)对学生对象列表进行分组,然后根据分组的学生属性创建对象(StudentSubject)。例如我有以下课程:

class Student{
        int id;
        String name;
        String subject;
        int score;

        public Student(int id, String name, String subject, int score) {
            this.id = id;
            this.name = name;
            this.subject = subject;
            this.score = score;
        }
}


class StudentSubject {
            String name;
            List<Result> results;
    }   



  class Result {
            String subjectName;
            int score;
    //getter setters
    }

所以对于以下输入:

id,name,subject,score  
1,John,Math,80
1,John,Physics,65
2,Thomas,Computer,55
2,Thomas,Biology,70

结果输出应为List&lt;StudentSubject&gt;,其属性设置自List&lt;Student&gt;。说:

1=[
            name = 'John'
            Result{subject='Math', score=80}, 
            Result{subject='Physics', score=65}, 
        ]
2=[
            name = 'Thomas'
            Result{subject='Computer', score=55}, 
            Result{subject='Biology', score=70}, 
        ]

如何先按 Id 分组,然后将属性设置为 Result 和 StudentSubject?

     public static void main(String[] args) {
            List<Student> studentList = Lists.newArrayList();
            studentList.add(new Student(1,"John","Math",80));
            studentList.add(new Student(1,"John","Physics",65));
            studentList.add(new Student(2,"Thomas","Computer",55));
            studentList.add(new Student(2,"Thomas","Biology",70));

// group by Id             studentList.stream().collect(Collectors.groupingBy(Student::getId));
//set result list
List<Result> resultList = studentList.stream().map(s -> {
            Result result = new Result();
            result.setSubjectName(s.getSubject());
            result.setScore(s.getScore());
            return result;

        }).collect(Collectors.toList());
    }

【问题讨论】:

标签: java java-8 java-stream


【解决方案1】:

在您的情况下,结果应该是List&lt;StudentSubject&gt;,您可以使用这种方式:

List<StudentSubject> resultList = studentList.stream()
        .collect(Collectors.groupingBy(Student::getId)) // until this point group by Id
        .entrySet()                                     // for each entry
        .stream()                                        
        .map(s -> new StudentSubject(                   // create a new StudentSubject
                s.getValue().get(0).getName(),          // you can use just the name of first element
                s.getValue().stream()                   // with a list of Result
                        .map(r -> new Result(r.getSubject(), r.getScore()))
                        .collect(Collectors.toList()))
        ).collect(Collectors.toList());                 // then collect every thing as a List

输出

StudentSubject{name='John', results=[Result{subjectName='Math', score=80}, Result{subjectName='Physics', score=65}]}
StudentSubject{name='Thomas', results=[Result{subjectName='Computer', score=55}, Result{subjectName='Biology', score=70}]}

【讨论】:

    【解决方案2】:

    您首先要查找的是 group-by 操作,然后是一个将学生对象转换为相应结果的映射器(就像在您的函数中一样):

    Map<String, List<Result>> resultList = studentList.stream()
            .collect(Collectors.groupingBy(Student::getName, Collectors.mapping(s -> {
                Result result = new Result();
                result.setSubjectName(s.getSubject());
                result.setScore(s.getScore());
                return result;
    
            }, Collectors.toList())));
    

    产生(略有不同的toString 实现):

    {Thomas=[Result [subjectName=Computer, score=55], 
             Result [subjectName=Biology, score=70]], 
     John=[Result [subjectName=Math, score=80], 
           Result [subjectName=Physics, score=65]]
    }
    

    【讨论】:

    • StudentSubject 类可能包含除名称之外的其他属性。那么如何获取具有属性集的 StudentSubject 列表呢?
    • 您需要按 id 而不是 name 对学生进行分组,并生成 StudentSubject 对象。
    • 最好的方法是确定是什么让学生对象独一无二,然后在 Student 中覆盖 both Object#equalsObject#hashCode。这样,您可以将Student::getName 替换为Function.identity()(或s -&gt; s)。整个学生对象将成为结果映射中的键
    猜你喜欢
    • 2020-05-20
    • 2022-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-01
    • 1970-01-01
    相关资源
    最近更新 更多