- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我是 Java 8 Stream API 的新手,但我想用它来解决以下问题。假设我有一个名为 InputRecord
的 POJO,其中包含 name
、fieldA
和 fieldB
属性,这些属性可以表示以下内容:
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条记录需要合并成两条记录,按名称分组,其中:
fieldA
求和fieldB
求和fieldC
属性,它是 fieldA
和 fieldB
的累加和相乘的结果。因此上面的结果是:
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 列表的一些好的方法/解决方案是什么?
我正在查看以下链接是否有帮助,但我无法尝试将 fieldA
和 fieldB
的收集器放在一起,以便为 形成一个新的收集器字段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/
以下面的列表为例: List input = List.of("FOO", "FOO", "FOO", "FOO", "FOO", "BAR", "BAR", "BAZ", "BAZ", "BAZ",
我有一个类似于下面的类 MyObject . public class MyObject { private String key; // not unique. multiple objec
我想获取按频率键控的数组值频率图。我能够得到相反的 - 按值键控的 map 。尝试切换参数,但 grouping by 不接受 Collector 作为第一个参数。 另一个问题,如何将 Map 实现更
我是 Java 8 Stream API 的新手,但我想用它来解决以下问题。假设我有一个名为 InputRecord 的 POJO,其中包含 name、fieldA 和 fieldB 属性,这些属性可
基准测试在 intel core i5, Ubuntu 下运行 java version "1.8.0_144" Java(TM) SE Runtime Environment (build 1.8.
我尝试使用流和收集器对值进行分组。我有我必须拆分的字符串列表。 我的数据: List stringList = new ArrayList<>(); stringList.add("Key:1,2,3
我想创建一个 Map来自 List的 Points并在映射中使用相同的 parentId 映射列表中的所有条目,例如 Map> . 我用了Collectors.toMap()但它没有编译: Map>
我已经实现了以下示例: Map> map = events.getItems().stream() .collect(Collectors.groupingBy(Event::getS
这个问题在这里已经有了答案: java 8 Collector is not a functional interface, who can tell why? (2 个回答) Java8: Usin
我想通过 Java 8 Stream 和 Collector 接口(interface)将 Map 转换为 ConcurrentHashMap,然后是我可以使用的两个选项。 第一个: Map mb =
如果我有一个对象列表(~200 个元素),只有几个唯一对象(~20 个元素)。 我只想拥有独特的值(value)。之间list.stream().collect(Collectors.toSet())
对于下面开发的 Java 8 代码,我收到以下错误。在此示例中,尝试将 Dish Name 的所有名称连接到一个变量中。使用下面的代码我得到了这个 "The method collect(Collec
我正在尝试使用rook在kubernetes集群上配置ceph,我已经运行了以下命令: kubectl apply -f common.yaml kubectl apply -f operator.y
这是我的流: Stream> futureStream = IntStream .iterate(1, n -> n n++) .mapToObj(pageNumber -> thi
Collector.of(Supplier 供应商、BiConsumer 累加器、BinaryOperator 组合器、Function 完成器、Characterstics...) Coll
按照常规思维,往一个map里put一个已经存在的key,会把原有的key对应的value值覆盖,然而通过一次线上问题,发现Java8中的Collectors.toMap反其道而行之,它默认给抛异常,
我想通过基于 LocalDateTime 的集合进行分组,但我只想获取小时,而不是分钟、秒... .collect(Collectors.groupingBy(cp -> getUpdateLocal
这个问题在这里已经有了答案: What is the point of "final class" in Java? (24 个答案) 关闭 3 年前。 为什么 Collectors 类在 Java
我有一个College具有嵌套静态类的类 Dept 学院 class College { private String collegeName; private Dept dept; public D
在Java库源代码中,Collectors#toList方法的定义如下: public static Collector> toList() { return new CollectorIm
我是一名优秀的程序员,十分优秀!