删除Java8中的重复对象,得到对象中String值的总和(第一个值需要在BigDecimal中转换)
Remove duplicate object in Java 8 and get the sum of String values in the object (first value need to convert in BigDecimal)
我有 class DTO,其中有 3 个字段。
我有一个 DTO 对象列表。
我想根据列表中的ID字段删除所有重复的对象,并得到字符串类型的值的总和。第一个值 转换为 Bigdecimal 然后添加(求和)重复的对象值。
注意:: 值是 class DTO
中的字符串格式
@AllArgsConstructor
static class DTO {
int id;
int year;
String value;
}
List<DTO> list = new ArrayList();
list.add(new DTO(1, 2020, "5.5"));
list.add(new DTO(1, 2020, "-8.0"));
list.add(new DTO(2, 2020, "1.5"));
list.add(new DTO(3, 2020, "4.5"));
list.add(new DTO(3, 2020, "1.5"));
list.add(new DTO(3, 2020, "-9.5"));
list.add(new DTO(4, 2020, "-3.5"));
list.add(new DTO(4, 2020, "7.5"));
list.add(new DTO(4, 2020, "5.5"));
list.add(new DTO(4, 2020, "-7.5"));
我尝试了各种流、收集器、groupby 等,但我迷路了。
这是我目前拥有的:
list.stream().collect(Collectors.groupingBy(e -> e.getId()), Collectors.reducing(BigDecimal.ZERO, DTO::getValue, BigDecimal.add()));
预计
DTO(1, 2021, "-2.5"); (value Sum of group 1)
DTO(2, 2021, "-1.5"); (value Sum of group 2)
DTO(3, 2021, "-3.5"); (value Sum of group 3)
DTO(4, 2021, "2"); (value Sum of group 4)
您可以创建一个添加两个 DTO
:
的方法
private static DTO add(DTO dto1, DTO dto2) {
BigDecimal bd1 = new BigDecimal(dto1.getValue());
BigDecimal bd2 = new BigDecimal(dto2.getValue());
return new DTO(dto1.getId(), dto1.getYear(), bd1.add(bd2).toString());
}
然后你可以 stream
按 id
分组并使用以前的方法减少:
private static List<DTO> add(List<DTO> list) {
Map<Integer, Optional<DTO>> map = list.stream()
.collect(Collectors.groupingBy(DTO::getId,
Collectors.reducing((d1, d2) -> add(d1, d2))));
return map.values().stream()
.filter(Optional::isPresent)
.map(Optional::get).toList();
}
测试:
List<DTO> list = List.of(
new DTO(1, 2020, "5.5"),
new DTO(1, 2020, "-8.0"),
new DTO(2, 2020, "1.5"),
new DTO(3, 2020, "4.5"),
new DTO(3, 2020, "1.5"),
new DTO(3, 2020, "-9.5"),
new DTO(4, 2020, "-3.5"),
new DTO(4, 2020, "7.5"),
new DTO(4, 2020, "5.5"),
new DTO(4, 2020, "-7.5"));
List<DTO> listAdded = add(list);
listAdded.forEach(System.out::println);
输出:
DTO[1, 2020, -2.5]
DTO[2, 2020, 1.5]
DTO[3, 2020, -3.5]
DTO[4, 2020, 2.0]
如果我这样做,我不会使用流,而是使用合并方法,该方法采用当前值并将其应用于现有值,在本例中是保存总和的实例。
List<DTO> list = List.of(new DTO(1, 2020, "5.5"),
new DTO(1, 2020, "-8.0"), new DTO(2, 2020, "1.5"),
new DTO(3, 2020, "4.5"), new DTO(3, 2020, "1.5"),
new DTO(3, 2020, "-9.5"), new DTO(4, 2020, "-3.5"),
new DTO(4, 2020, "7.5"), new DTO(4, 2020, "5.5"),
new DTO(4, 2020, "-7.5"));
Map<String, DTO> map = new HashMap<>();
for (DTO dto : list) {
map.merge(dto.getId() + "_" + dto.getYear(), dto, (sum, dt) -> new DTO(
sum.getId(), sum.getYear(),
new BigDecimal(sum.getValue())
.add(new BigDecimal((dt.getValue())))
.toString()));
}
map.values().forEach(System.out::println);
打印
DTO[1, 2020, -2.5]
DTO[2, 2020, 1.5]
DTO[3, 2020, -3.5]
DTO[4, 2020, 2.0]
如果您想将结果放入列表中,您可以这样做。
List<DTO> newList = new ArrayList<>(map.values());
除了 getter 和 setter 之外,我还使用以下 toString 进行输出。
@Override
public String toString() {
return "%s[%d, %d, %s]".formatted(this.getClass().getSimpleName(),id, year, value);
}
但如果你真的想使用流,那么你可以这样做。
- 流式传输对象
- 使用 toMap 收集
- 并使用 toMap 的合并方法对值求和。
Map<String, DTO> result = list.stream().collect(Collectors
.toMap(dto->dto.getId()+"_"+dto.getYear(), dto -> dto, (sum, dto) -> new DTO(
sum.getId(), sum.getYear(),
new BigDecimal(sum.getValue())
.add(new BigDecimal((dto.getValue())))
.toString())));
我有 class DTO,其中有 3 个字段。
我有一个 DTO 对象列表。
我想根据列表中的ID字段删除所有重复的对象,并得到字符串类型的值的总和。第一个值 转换为 Bigdecimal 然后添加(求和)重复的对象值。
注意:: 值是 class DTO
中的字符串格式@AllArgsConstructor
static class DTO {
int id;
int year;
String value;
}
List<DTO> list = new ArrayList();
list.add(new DTO(1, 2020, "5.5"));
list.add(new DTO(1, 2020, "-8.0"));
list.add(new DTO(2, 2020, "1.5"));
list.add(new DTO(3, 2020, "4.5"));
list.add(new DTO(3, 2020, "1.5"));
list.add(new DTO(3, 2020, "-9.5"));
list.add(new DTO(4, 2020, "-3.5"));
list.add(new DTO(4, 2020, "7.5"));
list.add(new DTO(4, 2020, "5.5"));
list.add(new DTO(4, 2020, "-7.5"));
我尝试了各种流、收集器、groupby 等,但我迷路了。
这是我目前拥有的:
list.stream().collect(Collectors.groupingBy(e -> e.getId()), Collectors.reducing(BigDecimal.ZERO, DTO::getValue, BigDecimal.add()));
预计
DTO(1, 2021, "-2.5"); (value Sum of group 1)
DTO(2, 2021, "-1.5"); (value Sum of group 2)
DTO(3, 2021, "-3.5"); (value Sum of group 3)
DTO(4, 2021, "2"); (value Sum of group 4)
您可以创建一个添加两个 DTO
:
private static DTO add(DTO dto1, DTO dto2) {
BigDecimal bd1 = new BigDecimal(dto1.getValue());
BigDecimal bd2 = new BigDecimal(dto2.getValue());
return new DTO(dto1.getId(), dto1.getYear(), bd1.add(bd2).toString());
}
然后你可以 stream
按 id
分组并使用以前的方法减少:
private static List<DTO> add(List<DTO> list) {
Map<Integer, Optional<DTO>> map = list.stream()
.collect(Collectors.groupingBy(DTO::getId,
Collectors.reducing((d1, d2) -> add(d1, d2))));
return map.values().stream()
.filter(Optional::isPresent)
.map(Optional::get).toList();
}
测试:
List<DTO> list = List.of(
new DTO(1, 2020, "5.5"),
new DTO(1, 2020, "-8.0"),
new DTO(2, 2020, "1.5"),
new DTO(3, 2020, "4.5"),
new DTO(3, 2020, "1.5"),
new DTO(3, 2020, "-9.5"),
new DTO(4, 2020, "-3.5"),
new DTO(4, 2020, "7.5"),
new DTO(4, 2020, "5.5"),
new DTO(4, 2020, "-7.5"));
List<DTO> listAdded = add(list);
listAdded.forEach(System.out::println);
输出:
DTO[1, 2020, -2.5]
DTO[2, 2020, 1.5]
DTO[3, 2020, -3.5]
DTO[4, 2020, 2.0]
如果我这样做,我不会使用流,而是使用合并方法,该方法采用当前值并将其应用于现有值,在本例中是保存总和的实例。
List<DTO> list = List.of(new DTO(1, 2020, "5.5"),
new DTO(1, 2020, "-8.0"), new DTO(2, 2020, "1.5"),
new DTO(3, 2020, "4.5"), new DTO(3, 2020, "1.5"),
new DTO(3, 2020, "-9.5"), new DTO(4, 2020, "-3.5"),
new DTO(4, 2020, "7.5"), new DTO(4, 2020, "5.5"),
new DTO(4, 2020, "-7.5"));
Map<String, DTO> map = new HashMap<>();
for (DTO dto : list) {
map.merge(dto.getId() + "_" + dto.getYear(), dto, (sum, dt) -> new DTO(
sum.getId(), sum.getYear(),
new BigDecimal(sum.getValue())
.add(new BigDecimal((dt.getValue())))
.toString()));
}
map.values().forEach(System.out::println);
打印
DTO[1, 2020, -2.5]
DTO[2, 2020, 1.5]
DTO[3, 2020, -3.5]
DTO[4, 2020, 2.0]
如果您想将结果放入列表中,您可以这样做。
List<DTO> newList = new ArrayList<>(map.values());
除了 getter 和 setter 之外,我还使用以下 toString 进行输出。
@Override
public String toString() {
return "%s[%d, %d, %s]".formatted(this.getClass().getSimpleName(),id, year, value);
}
但如果你真的想使用流,那么你可以这样做。
- 流式传输对象
- 使用 toMap 收集
- 并使用 toMap 的合并方法对值求和。
Map<String, DTO> result = list.stream().collect(Collectors
.toMap(dto->dto.getId()+"_"+dto.getYear(), dto -> dto, (sum, dto) -> new DTO(
sum.getId(), sum.getYear(),
new BigDecimal(sum.getValue())
.add(new BigDecimal((dto.getValue())))
.toString())));