Java 8、合并两个或多个嵌套列表

Java 8 , Merge two or more nested list

我需要合并 inner/nested 数组:

Pojo 结构

要求:如果有 2 个列表或 X 个列表要合并,我如何在 java 8 中实现?合并嵌套数组的最简单方法是什么?

private class Student {
    private int studentId;
    private List<Marks> markList = new ArrayList<>();
}

private class Marks {
    private Integer subjectId;
    private String subjectName;
    private Integer mark;
}
 

需要合并以下 2 条记录:

{
  "studentId": 1,
  "Marks": [
    {
      "subjectId": 1,
      "mark": 10
    },
    {
      "subjectId": 2,
      "mark": 10
    }
  ]
}
{
  "studentId": 1,
  "Marks": [
    {
      "subjectId": 1,
      "mark": 15
    },
    {
      "subjectId": 3,
      "mark": 10
    }
  ]
}

给出最终预期结果为:

{
  "studentId": 1,
  "Marks": [
    {
      "subjectId": 1,
      "mark": 25 //Addition of record 1 and 2
    },
    {
      "subjectId": 2,
      "mark": 10
    }
    {
      "subjectId": 3,
      "mark": 10
    }
  ]
}

您可以使用终端操作 collect(Collectors.toMap()) 通过 ID 映射每个学生,然后处理冲突情况以将不同的学生实例合并为一个新实例。

那时,当实例化一个新的 Student 时,您可以实现一个嵌套流来合并两个冲突实例的标记。通过应用第二个 collect(Collectors.toMap()),您可以按主题 ID 对标记进行分组,然后通过合并标记的值再次处理冲突案例。

在下面的代码片段中,我通过添加第二个 Student:

丰富了您的测试用例
List<Student> list = new ArrayList<>(List.of(
        new Student(1, new ArrayList<>(List.of(new Marks(1, 10), new Marks(2, 10)))),
        new Student(1, new ArrayList<>(List.of(new Marks(1, 15), new Marks(3, 10)))),
        new Student(2, new ArrayList<>(List.of(new Marks(1, 5), new Marks(2, 10)))),
        new Student(2, new ArrayList<>(List.of(new Marks(2, 5), new Marks(3, 10))))
));

//Temporary map
Map<Integer, Student> mapTemp = list.stream()
        .collect(Collectors.toMap(Student::getStudentId,                                        //grouping by student id
                Function.identity(),                                                            //setting as value the student
                (s1, s2) -> new Student(s1.getStudentId(), new ArrayList<>(                     //Creating a new Student whose list of marks is given by the merged marks of the two colliding students
                        Stream.concat(s1.getMarkList().stream(), s2.getMarkList().stream())     //Chaining the two lists of marks into a single stream
                                .collect(Collectors.toMap(Marks::getSubjectId,                  //Grouping by the marks by the subject id
                                        Function.identity(),                                    //Setting as value the mark
                                        (m1, m2) -> new Marks(m1.getSubjectId(), m1.getMark() + m2.getMark())))  //Handling the colliding marks by summing them together
                                .values())))                                                    //Retrieving the collection of merged marks
        );

//Result list with the merged students
List listRes = new ArrayList(mapTemp.values());
System.out.println(listRes);

这里还有一个link来测试上面的代码:

https://ideone.com/0i6ZqG

由于您使用的是嵌套列表,因此解决问题的最佳方法是使用 MAP

List<Student> studentList = new ArrayList<>();
        studentList.add(new Student(1,new ArrayList<Marks>(){{
            add(new Marks(1,10));
            add(new Marks(2,8));
        }}));
        studentList.add(new Student(1,new ArrayList<Marks>(){{
            add(new Marks(1,5));
            add(new Marks(2,8));
            add(new Marks(3,6));
        }}));

您可以添加更多学生和他们的分数以进行更多测试。

主要的 objective 是为每个学生计算每个科目的分数并将其存储到 Map 对象中。

       //Storing the latest merged marks for each students .
        Map<Integer,List<Marks>> listMap = new HashMap<Integer,List<Marks>>();
        for(Student student: studentList){

            if(!listMap.containsKey(student.getStudentId())){
                listMap.put(student.getStudentId(),student.getMarkList());
            }else{
                /** storing individual marks of each subject for this student
                 * <k,v> = <SubjectID ,Marks>
                */
                Map<Integer,Integer> merge = new HashMap<>();

                // storing existing marks of any subjectID.
                for(Marks oldMark : listMap.get(student.getStudentId())){
                    merge.put(oldMark.getSubjectId(),oldMark.getMark());
                }
                // calculating new marks as per each subject id
                for(Marks newMark : student.getMarkList()){
                    // checking whether subject has any old values or not .
                    int val = merge.get(newMark.getSubjectId()) == null ? 0: merge.get(newMark.getSubjectId()) ;
                    merge.put(newMark.getSubjectId(),val+newMark.getMark());
                }

                //creating new merged marks list
                List<Marks> temp = new ArrayList<Marks>();
                for(int sid : merge.keySet()){
                    temp.add(new Marks(sid,merge.get(sid)));
                }
                // updating the main map with new merged values
                listMap.put(student.getStudentId(),temp);
            }
        }

获得最终合并地图后,如果需要,您可以将其转换为学生类型的列表。