Java 如何通过按结果分组创建新对象

Java 如何通过按结果分组创建新对象,java,java-8,grouping,Java,Java 8,Grouping,例如 总结之后,我需要创建一个Sales类型的新对象,具有如下所示的总计(group by的sum result) { "month" : "Total", "year": "2000", "state" : "State1", "city" : "City1", "sales" : "15" } 所以我在Sales中创建了相应的构造函数并尝试了 list.stream() .collect(groupingBy(Sale::getState,

例如

总结之后,我需要创建一个Sales类型的新对象,具有如下所示的总计(group by的sum result)

{
"month" : "Total",
"year":  "2000",
"state" : "State1",
"city" :  "City1",
"sales" : "15"
}
所以我在Sales中创建了相应的构造函数并尝试了

list.stream()
    .collect(groupingBy(Sale::getState,
                        groupingBy(Sale::getCity,
                                   summingInt(Sale::getSales).Collectors.mapping(e -> new Sales ("Total","2000","State1","City1",<summingInt result should come here>),
                                Collectors.toList()))));  
list.stream()
.collect(分组依据)(销售::getState,
groupingBy(销售::getCity,
summingit(Sale::getSales).Collectors.mapping(e->newsales(“总计”、“2000”、“状态1”、“城市1”),
收藏家;
如何在Java 8中实现上述格式?

您可以这样做:

您可以使用带有合并功能的
toMap
收集器,而不是第二个
groupingBy

list.stream()
    .collect(Collectors.groupingBy(Sales::getState,
        Collectors.toMap(Sales::getCity,Function.identity(),                              
              (s1, s2) -> new Sales(s1.month,...,s1.getSales() + s2.getSales()))));
您可以这样做:

您可以使用带有合并功能的
toMap
收集器,而不是第二个
groupingBy

list.stream()
    .collect(Collectors.groupingBy(Sales::getState,
        Collectors.toMap(Sales::getCity,Function.identity(),                              
              (s1, s2) -> new Sales(s1.month,...,s1.getSales() + s2.getSales()))));

你的方向是正确的。唯一需要做的是最后一步,将所有销售编号合并到一个对象中。不能只使用
summingit
,因为它只返回int,而没有其他字段来构造对象。可以通过使用
reduce
构造初始对象并添加字段值来实现这一点:

list.stream()
    .collect(groupingBy(Sale::getState,
                        groupingBy(Sale::getCity,
                                   reducing( (a, b) -> new Sale(a.getMonth(), a.getYear(), a.getState(), a.getCity(), a.getSale() + b.getSale()) ))));
如果您不关心月份和年份,还可以创建一个标识对象(初始对象)并只向其中添加销售额。它可以减少创建的临时对象的数量:

list.stream()
    .collect(groupingBy(Sale::getState,
                        groupingBy(Sale::getCity,
                                   reducing(new Sale("Total", "2000", "", "", 0), (a, b) -> {
                                            a.setState(b.getState());
                                            a.setCity(b.getCity()); 
                                            a.setSales(a.getSales() + b.getSales()); 
                                            return a;
                                   } ))));

确保所有对象的年和月都相同,否则它将丢失(除非您对此不在意)。

您的方向是正确的。唯一需要做的是最后一步,将所有销售编号合并到一个对象中。不能只使用
summingit
,因为它只返回int,而没有其他字段来构造对象。可以通过使用
reduce
构造初始对象并添加字段值来实现这一点:

list.stream()
    .collect(groupingBy(Sale::getState,
                        groupingBy(Sale::getCity,
                                   reducing( (a, b) -> new Sale(a.getMonth(), a.getYear(), a.getState(), a.getCity(), a.getSale() + b.getSale()) ))));
如果您不关心月份和年份,还可以创建一个标识对象(初始对象)并只向其中添加销售额。它可以减少创建的临时对象的数量:

list.stream()
    .collect(groupingBy(Sale::getState,
                        groupingBy(Sale::getCity,
                                   reducing(new Sale("Total", "2000", "", "", 0), (a, b) -> {
                                            a.setState(b.getState());
                                            a.setCity(b.getCity()); 
                                            a.setSales(a.getSales() + b.getSales()); 
                                            return a;
                                   } ))));

确保所有对象的年和月都相同,否则将丢失(除非您不在乎此情况)。

要清楚,您需要按州和城市分组,然后将销售额设置为组内所有销售额的总和?是的,正确@texasbruce,因此对于州1,对于城市1,总计为15,使用这些值,我想创建一个单独的销售对象,对于其他州和城市,同样要清楚,你想按州和城市分组,然后将销售额设置为组内所有销售额的总和?是的,正确@texasbruce,因此对于州1,城市1,总计为15,使用这些值,我想创建一个单独的销售对象,对于其他州,同样,citiesOP想创建新对象。此代码将覆盖第一个对象的Sales@texasbruce,感谢您这么说。OP想创建新对象。此代码将覆盖第一个对象的Sales@texasbruce,谢谢你这么说。