Java中对象的聚合列表

Java中对象的聚合列表,java,java-8,aggregate-functions,java-stream,Java,Java 8,Aggregate Functions,Java Stream,Java中是否有任何聚合器函数来执行以下聚合 Person { String name; String subject; String department; Long mark1; Long mark2; Long mark3; } 列表包含如下数据 Name |Subject |Department |Mark1 |Mark2 |Mark3 --------|-----------|-----------|-------|--

Java中是否有任何聚合器函数来执行以下聚合

Person {
    String name;
    String subject;
    String department;
    Long mark1;
    Long mark2;
    Long mark3;
}
列表包含如下数据

Name |Subject |Department |Mark1 |Mark2 |Mark3 --------|-----------|-----------|-------|-------|----- Clark |English |DEP1 |7 |8 |6 Michel |English |DEP1 |6 |4 |7 Dave |Maths |DEP2 |3 |5 |6 Mario |Maths |DEP1 |9 |7 |8
private static List<Person> getGrouped(List<Person> origList) {
    Map<String, Person> grpMap = new HashMap<String, Person>();

    for (Person person : origList) {
        String key = person.getDepartment() + person.getSubject();
        if (grpMap.containsKey(key)) {
            Person grpdPerson = grpMap.get(key);
            grpdPerson.setMark1(grpdPerson.getMark1() + person.getMark1());
            grpdPerson.setMark2(grpdPerson.getMark2() + person.getMark2());
            grpdPerson.setMark3(grpdPerson.getMark3() + person.getMark3());
        } else {
            grpMap.put(key, person);
        }
    }
    return new ArrayList<Person>(grpMap.values());
}
姓名|科目|部门|标记1 |标记2 |标记3 --------|-----------|-----------|-------|-------|----- 克拉克|英语| DEP1 | 7 | 8 | 6 米歇尔|英语| DEP1 | 6 | 4 | 7 戴夫|数学| DEP2 | 3 | 5 | 6 马里奥|数学| DEP1 | 9 | 7 | 8 聚合条件为Subject&Dep。结果对象需要

Subject |Department |Mark1 |Mark2 |Mark3 ----------- |-----------|-------|-------|----- English |DEP1 |13 |12 |13 Maths |DEP2 |3 |5 |6 Maths |DEP1 |9 |7 |8 科目|部门|标记1 |标记2 |标记3 ----------- |-----------|-------|-------|----- 英语| DEP1 | 13 | 12 | 13 数学| DEP2 | 3 | 5 | 6 数学| DEP1 | 9 | 7 | 8 可以通过手动迭代列表并创建聚合列表来实现此聚合。示例如下

Name |Subject |Department |Mark1 |Mark2 |Mark3 --------|-----------|-----------|-------|-------|----- Clark |English |DEP1 |7 |8 |6 Michel |English |DEP1 |6 |4 |7 Dave |Maths |DEP2 |3 |5 |6 Mario |Maths |DEP1 |9 |7 |8
private static List<Person> getGrouped(List<Person> origList) {
    Map<String, Person> grpMap = new HashMap<String, Person>();

    for (Person person : origList) {
        String key = person.getDepartment() + person.getSubject();
        if (grpMap.containsKey(key)) {
            Person grpdPerson = grpMap.get(key);
            grpdPerson.setMark1(grpdPerson.getMark1() + person.getMark1());
            grpdPerson.setMark2(grpdPerson.getMark2() + person.getMark2());
            grpdPerson.setMark3(grpdPerson.getMark3() + person.getMark3());
        } else {
            grpMap.put(key, person);
        }
    }
    return new ArrayList<Person>(grpMap.values());
}
私有静态列表getGrouped(List origList){
Map grpMap=newhashmap();
for(个人:origList){
字符串键=person.getDepartment()+person.getSubject();
if(grpMap.CONTANSKEY(关键)){
Person grpdPerson=grpMap.get(键);
grpdPerson.setMark1(grpdPerson.getMark1()+person.getMark1());
grpdPerson.setMark2(grpdPerson.getMark2()+person.getMark2());
grpdPerson.setMark3(grpdPerson.getMark3()+person.getMark3());
}否则{
grpMap.put(钥匙、人员);
}
}
返回新的ArrayList(grpMap.values());
}
但是,我们是否可以利用Java 8的任何聚合功能或特性?

您可以使用。聚合标记1的样本如下所示

public class Test {

    static class Person {
        Person(String name, String subject, String department, Long mark1, Long mark2, Long mark3) {
            this.name = name;
            this.subject = subject;
            this.department = department;
            this.mark1 = mark1;
            this.mark2 = mark2;
            this.mark3= mark3;
        }
            String name;
            String subject;
            String department;
            Long mark1;
            Long mark2;
            Long mark3;

            String group() {
                return subject+department;
            }

            Long getMark1() {
                return mark1;
            }
    }

      public static void main(String[] args)
      {
        List<Person> list = new ArrayList<Test.Person>();
        list.add(new Test.Person("Clark","English","DEP1",7l,8l,6l));
        list.add(new Test.Person("Michel","English","DEP1",6l,4l,7l));
        list.add(new Test.Person("Dave","Maths","DEP2",3l,5l,6l));
        list.add(new Test.Person("Mario","Maths","DEP1",9l,7l,8l));

        Map<String, Long> groups = list.stream().collect(Collectors.groupingBy(Person::group, Collectors.reducing(
                    0l, Person::getMark1, Long::sum)));

        //Or alternatively as suggested by Holger 
        Map<String, Long> groupsNew = list.stream().collect(Collectors.groupingBy(Person::group, Collectors.summingLong(Person::getMark1)));

        System.out.println(groups);

      }

}
公共类测试{
静态类人{
人员(字符串名称、字符串主题、字符串部门、长标记1、长标记2、长标记3){
this.name=名称;
this.subject=主语;
这个部门=部门;
this.mark1=mark1;
this.mark2=mark2;
这个.mark3=mark3;
}
字符串名;
字符串主题;
弦乐部;
长标记1;
长标记2;
长标记3;
字符串组(){
返回主题+部门;
}
Long getMark1(){
返回标记1;
}
}
公共静态void main(字符串[]args)
{
列表=新的ArrayList();
添加(新测试人员(“克拉克”、“英语”、“DEP1”、7l、8l、6l”);
添加(新的测试人员(“Michel”、“English”、“DEP1”、6l、4l、7l”);
添加(新的测试人员(“Dave”、“数学”、“DEP2”、3l、5l、6l”);
添加(新的测试人员(“马里奥”、“数学”、“DEP1”、9l、7l、8l”);
映射组=list.stream().collect(Collectors.groupingBy(Person::group,Collectors.com)(
0l,Person::getMark1,Long::sum));
//或者按照霍尔格的建议
Map groupsNew=list.stream().collect(Collectors.groupingBy(Person::group,Collectors.summingLong(Person::getMark1));
系统输出打印项次(组);
}
}

仍在考虑通过单个函数生成输出。将在完成后更新。

使用JDK中的标准收集器,可以这样做(假设创建了
Tuple3
类):

在这种情况下,您可能还希望使用
toMap
收集器使用另一个变量。逻辑保持不变,映射值的函数将创建一个映射,其中包含部门作为键,学生的成绩作为值。合并功能将负责添加或更新映射

Map<String, Map<String, Tuple3<Long, Long, Long>>> res3 =
        persons.stream()
               .collect(toMap(p -> p.subject,
                              p -> {
                                  Map<String, Tuple3<Long, Long, Long>> value = new HashMap<>();
                                  value.put(p.department, new Tuple3<>(p.mark1, p.mark2, p.mark3));
                                  return value;
                              },
                              (v1, v2) -> {
                                   v2.forEach((k, v) -> v1.merge(k, v, (t1, t2) -> new Tuple3<>(t1.e1 + t2.e1, t1.e2 + t2.e2, t1.e3 + t2.e3)));
                                   return v1;
                              }
               ));
Map res3=
人流()
.收集(toMap)(p->p.subject,
p->{
Map value=newhashmap();
value.put(p.department,新元组3(p.mark1,p.mark2,p.mark3));
返回值;
},
(v1,v2)->{
v2.forEach((k,v)->v1.merge(k,v,(t1,t2)->新元组3(t1.e1+t2.e1,t1.e2+t2.e2,t1.e3+t2.e3));
返回v1;
}
));
当然,您可以对这些解决方案的“美”提出疑问,也许您想引入一个自定义收集器或自定义类,以使意图更加明确。

使用来自自定义密钥类的方法,我的建议如下:

    Map<DepSubject, Grades> map = persons.stream().
            collect(Collectors.groupingBy(x -> new DepSubject(x.department, x.subject),
            Collectors.reducing(
                    new Grades(0, 0, 0),
                    y -> new Grades(y.mark1, y.mark2, y.mark3),
                    (x, y) -> new Grades(x.m1 + y.m1, x.m2 + y.m2, x.m3 + y.m3)
            )));
也可以将结果收集到列表中。这样,自定义类
DepSubject
Grades
仅用于中间操作:

    List<Person> list = persons.stream().
            collect(Collectors.collectingAndThen(
                    Collectors.groupingBy(x -> new DepSubject(x.department, x.subject),
                            Collectors.reducing(
                                    new Grades(0, 0, 0),
                                    y -> new Grades(y.mark1, y.mark2, y.mark3),
                                    (x, y) -> new Grades(x.m1 + y.m1, x.m2 + y.m2, x.m3 + y.m3)
                            )),
                    map -> map.entrySet().stream()
                              .map(e -> new Person(null, e.getKey().subject, e.getKey().department, e.getValue().m1, e.getValue().m2, e.getValue().m3))
                              .collect(Collectors.toList())
            ));
List List=persons.stream()。
收集(收集器。收集然后(
收集者。分组方式(x->new DepSubject(x.department,x.subject),
还原剂(
新职系(0,0,0),,
y->新等级(y.mark1、y.mark2、y.mark3),
(x,y)->新等级(x.m1+y.m1,x.m2+y.m2,x.m3+y.m3)
)),
map->map.entrySet().stream()
.map(e->newperson(null,e.getKey().subject,e.getKey().department,e.getValue().m1,e.getValue().m2,e.getValue().m3))
.collect(收集器.toList())
));
您还可以将groupingBy逻辑提取到函数中:

private static <T> List<Person> groupBy(List<Person> persons, Function<Person,T> function, BiFunction<T,Grades,Person> biFunction) {
    return persons.stream().
            collect(Collectors.collectingAndThen(
                    Collectors.groupingBy(function,
                            Collectors.reducing(
                                    new Grades(0, 0, 0),
                                    y -> new Grades(y.mark1, y.mark2, y.mark3),
                                    (x, y) -> new Grades(x.m1 + y.m1, x.m2 + y.m2, x.m3 + y.m3)
                            )),
                    map -> map.entrySet().stream()
                              .map(e -> biFunction.apply(e.getKey(),e.getValue()))
                              .collect(Collectors.toList())
            ));
}
private static List groupBy(列出人员、函数、双函数){
return persons.stream()。
收集(收集器。收集然后(
收集器。分组方式(函数,
还原剂(
新职系(0,0,0),,
y->新年级(y.ma)
private static <T> List<Person> groupBy(List<Person> persons, Function<Person,T> function, BiFunction<T,Grades,Person> biFunction) {
    return persons.stream().
            collect(Collectors.collectingAndThen(
                    Collectors.groupingBy(function,
                            Collectors.reducing(
                                    new Grades(0, 0, 0),
                                    y -> new Grades(y.mark1, y.mark2, y.mark3),
                                    (x, y) -> new Grades(x.m1 + y.m1, x.m2 + y.m2, x.m3 + y.m3)
                            )),
                    map -> map.entrySet().stream()
                              .map(e -> biFunction.apply(e.getKey(),e.getValue()))
                              .collect(Collectors.toList())
            ));
}
    List<Person> list = groupBy(persons,
            x -> new DepSubject(x.department, x.subject),
            (depSubject,grades) -> new Person(null, depSubject.subject, depSubject.department, grades.m1, grades.m2, grades.m3));
    List<Person> list2 = groupBy(persons,
            Person::getSubject,
            (subject,grades) -> new Person(null,subject, null, grades.m1, grades.m2, grades.m3));