在处理数据库集合时,会有这样的场景,根据List中的某个属性来groupby,单个条件的很简单,示例到处都有,不在赘述,这里记录一下,当需要根据多个条件来groupby,并且对其中某个属性求和,最终返回当前List的情况,话不多说,先上代码
首先是测试对象
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class TestDTO {
private Long id;
private String erp;
private Date date;
private BigDecimal hours;
}
然后是实现类
TestDTO d1 = TestDTO.builder().erp("a").hours(new BigDecimal("1.2")).date(sdf.parse("2021-05-21")).build();
TestDTO d2 = TestDTO.builder().erp("a").hours(new BigDecimal("1.0")).date(sdf.parse("2021-05-21")).build();
TestDTO d3 = TestDTO.builder().erp("a").hours(new BigDecimal("1.0")).date(sdf.parse("2021-05-11")).build();
TestDTO d4 = TestDTO.builder().erp("b").hours(new BigDecimal("2.2")).date(sdf.parse("2021-05-21")).build();
TestDTO d5 = TestDTO.builder().erp("b").hours(new BigDecimal("2.0")).date(sdf.parse("2021-05-19")).build();
TestDTO d6 = TestDTO.builder().erp("b").hours(new BigDecimal("2.0")).date(sdf.parse("2021-05-19")).build();
TestDTO d7 = TestDTO.builder().erp("c").hours(new BigDecimal("8.0")).date(sdf.parse("2021-05-19")).build();
List<TestDTO> list = List.of(d1,d2,d3,d4,d5,d6,d7);
Map<String,List<TestDTO>> map = list.stream().collect(Collectors.groupingBy(d->d.getErp()+"#"+sdf.format(d.getDate())));
System.out.println(JSON.toJSONString(map));
List<TestDTO> ret = map.keySet().stream().map(x->{
String[] key = x.split("#");
BigDecimal sum =map.get(x).stream().map(TestDTO::getHours).reduce(BigDecimal.ZERO,BigDecimal::add);
Date date = map.get(x).get(0).getDate();
String erp = map.get(x).get(0).getErp();
TestDTO dto = null;
try {
dto = TestDTO.builder().erp(erp).date(sdf.parse(key[1])).hours(sum).build();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return dto;
}).collect(Collectors.toList());
System.out.println(JSON.toJSONString(ret));
我的思路是,首先把list按照erp+date分组,再把分组后的list打散到重新生成新的list,每一组重新生成时,把各自组内list的hour进行累加,还原出一个最终结果