gpt4 book ai didi

Java 8 流 : Defining collectors based on other collectors

转载 作者:行者123 更新时间:2023-11-30 06:46:21 26 4
gpt4 key购买 nike

我是 Java 8 Stream API 的新手,但我想用它来解决以下问题。假设我有一个名为 InputRecord 的 POJO,其中包含 namefieldAfieldB 属性,这些属性可以表示以下内容:

name | fieldA | fieldB
----------------------
A | 100 | 1.1
A | 150 | 2.0
B | 200 | 1.5
A | 120 | 1.3

InputRecord 看起来像:

public class InputRecord {
private String name;
private Integer fieldA;
private BigDecimal fieldB;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getFieldA() {
return fieldA;
}

public void setFieldA(Integer fieldA) {
this.fieldA = fieldA;
}

public BigDecimal getFieldB() {
return fieldB;
}

public void setFieldB(BigDecimal fieldB) {
this.fieldB = fieldB;
}
}

上面那4条记录需要合并成两条记录,按名称分组,其中:

  1. 属性fieldA求和
  2. 属性fieldB求和
  3. 组合记录包括一个 fieldC 属性,它是 fieldAfieldB 的累加和相乘的结果。

因此上面的结果是:

name | sumOfFieldA | sumOfFieldB | fieldC (sumOfFieldA*sumOfFieldB)
-------------------------------------------------------------------
A | 370 | 4.4 | 1628
B | 200 | 1.5 | 300

一个名为 OutputRecord 的不同 POJO 将代表组合记录的每一行记录:

public class OutputRecord {
private String name;
private Integer sumOfFieldA;
private BigDecimal sumOfFieldB;
private BigDecimal fieldC;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getSumOfFieldA() {
return sumOfFieldA;
}

public void setSumOfFieldA(Integer sumOfFieldA) {
this.sumOfFieldA = sumOfFieldA;
}

public BigDecimal getSumOfFieldB() {
return sumOfFieldB;
}

public void setSumOfFieldB(BigDecimal sumOfFieldB) {
this.sumOfFieldB = sumOfFieldB;
}

public BigDecimal getFieldC() {
return fieldC;
}

public void setFieldC(BigDecimal fieldC) {
this.fieldC = fieldC;
}
}

将 InputRecords 列表转换为 OutputRecords 列表的一些好的方法/解决方案是什么?

我正在查看以下链接是否有帮助,但我无法尝试将 fieldAfieldB 的收集器放在一起,以便为 形成一个新的收集器字段C: Java 8 Stream: groupingBy with multiple Collectors

Collector<InputRecord, ?, Integer> fieldACollector = Collectors.summingInt(InputRecord::getFieldA);
Collector<InputRecord, ?, BigDecimal> fieldBCollector = Collectors.reducing(BigDecimal.ZERO, InputRecord::getFieldB, BigDecimal::add);

List<Collector<InputRecord, ?, ?>> collectors = Arrays.asList(fieldACollector, fieldBCollector); // need a fieldCCollector object in the list

然后,collectors 对象将用于创建 complexCollector 对象(根据 Tagir Valeev 在上述链接中接受的答案)。

最佳答案

对我来说,最干净的方法是为此构建一个自定义收集器。这里有多行代码,但是你可以把它隐藏在一个方法下,所以你的最终操作是这样的:

Collection<OutputRecord> output = List.of(first, second, thrid, fourth)
.stream()
.parallel()
.collect(toOutputRecords());

虽然实际的 toOutputRecords 是:

 private static Collector<InputRecord, ?, Collection<OutputRecord>> toOutputRecords() {
class Acc {

Map<String, OutputRecord> map = new HashMap<>();

void add(InputRecord elem) {
String value = elem.getName();
// constructor without fieldC since you compute it at the end
OutputRecord record = new OutputRecord(value, elem.getFieldA(), elem.getFieldB());
mergeIntoMap(map, value, record);
}

Acc merge(Acc right) {
Map<String, OutputRecord> leftMap = map;
Map<String, OutputRecord> rightMap = right.map;

for (Entry<String, OutputRecord> entry : rightMap.entrySet()) {
mergeIntoMap(leftMap, entry.getKey(), entry.getValue());
}
return this;
}

private void mergeIntoMap(Map<String, OutputRecord> map, String value, OutputRecord record) {

map.merge(value, record, (left, right) -> {
left.setSumOfFieldA(left.getSumOfFieldA() + right.getSumOfFieldA());
left.setSumOfFieldB(left.getSumOfFieldB().add(right.getSumOfFieldB()));

return left;
});
}

public Collection<OutputRecord> finisher() {
for (Entry<String, OutputRecord> e : map.entrySet()) {
OutputRecord output = e.getValue();
output.setFieldC(output.getSumOfFieldB().multiply(BigDecimal.valueOf(output.getSumOfFieldA())));
}
return map.values();
}

}
return Collector.of(Acc::new, Acc::add, Acc::merge, Acc::finisher);
}

关于Java 8 流 : Defining collectors based on other collectors,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47645399/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com