聚合两个对象列表的最佳方法是什么?

时间:2021-04-08 05:10:47

标签: java

我有两个包含学生对象的列表。我想将 objects.status 属性聚合到两个 studentId 相似的列表中。

承诺List A中的status属性总是null,List B中的status属性不是null

Student List A:
id:123, name: noname, status: null, address: xxxx, contact: xxx, ....
id:124, name: noname, status: null, address: xxxx, contact: xxx, ....
id:125, name: noname, status: null, address: xxxx, contact: xxx, ....

Student List B:
id:123, name: null, status: accepted, address: null, contact: null, ....
id:124, name: null, status: not-accepted, address: null, contact: null, ....
id:125, name: null, status: accepted, address: null, contact: null, ....


Aggregated list:
id:123, name: noname, status: accepeted, address: xxxx, contact: xxx, ....
id:124, name: noname, status: not-accepted, address: xxxx, contact: xxx, ....
id:125, name: noname, status: accepted, address: xxxx, contact: xxx, ....

通常,我会使用两个 for 循环来聚合两个结果。有没有更好的方法来做到这一点?

3 个答案:

答案 0 :(得分:1)

对于流,您可以使用 groupingBy 的组合对相似的 id 进行分组,并通过选择具有非空状态的元素来减少分组的元素:

Stream.concat(a.stream(),b.stream())
      .collect(Collectors.groupingBy(Student::getId, 
                                     Collectors.reducing((x,y) -> (x.getStatus() != null) ? x: y)))
      .values()
      .stream()
      .filter(Optional::isPresent)
      .map(Optional::get)
      .collect(Collectors.toList()); // returns a list of student objects.

我不确定这是否比传统的 for 循环“更好”,但这是一种方法。

答案 1 :(得分:0)

您可以将一个列表放入集合中。

并更新第二个/聚合列表,如下所示。

Map<Long, Student> uniqueStudents = new HashMap<>();
for(Student st : listA)
uniqueStudents.put(st.getId(), st);
for(int i = 0; i < listB.size(); i++)
 {
    Student studentB = listB.get(i);
    Student studentA = uniqueStudents.get(studentB.getId());
    // do aggregation.
 }

答案 2 :(得分:0)

/*
approach : step 1> make a hash map of id->student from list A
           step 2> traverse list B, find out the match from map and
                   make a combined record from list and map of same id,
                   and put that in the output list.

we can assume the existence of the Student class.
*/
List<Student> aggregate(List<Student> A, List<Student> B) {
    Map<String, Student> hm = new HashMap<>();
    for (Student student : A) {
        hm.put(student.getId(), student);
    }
    List<Student> combined = new ArrayList<>();
    for (Student student : B) {
        if (hm.containsKey(student.getId())) {
            Student s1 = new Student(student);//this copy constructor should present in 
                                              //the Student class
            Student s2 = hm.get(student.getId());
            //now combine both of them
            // in this way we are combined all fields which is null in any list
            if (s2.getName() != null) {
                s1.setName(s2.getName());
            }
            if (s2.getStatus() != null) {
                s1.setStatus(s2.getStatus());
            }
            if (s2.getAddress() != null) {
                s1.setAddress(s2.getAddress());
            }
            if (s2.getContact() != null) {
                s1.setContact(s2.getContact());
            }
            combined.add(s1);
        }
    }
    return combined;
}