我有一个对象流。我想将它们分组并计算从对象函数获得的值之和的除法。
import java.util.Map;
import java.util.stream.Stream;
record TestRecord(String type, int a, int b) {
public int getA() { return a; }
public int getB() { return b; }
}
public class Test {
public static void main(String[] args) {
Stream<TestRecord> testRecords = Stream.of(
new TestRecord("TYPE1", 1, 2),
new TestRecord("TYPE1", 3, 4),
new TestRecord("TYPE2", 5, 6),
new TestRecord("TYPE2", 7, 8),
new TestRecord("TYPE2", 9, 10)
);
}
//It should return {TYPE1= (4/6), TYPE2 = (21 / 24)}
//TYPE1= (1+3 / 2+4), TYPE2 = ((5+7+9) / (6+8+10))
public static Map<String, Double> myFunction(Stream<TestRecord> testRecordStream) {
//TODO
return null;
}
}
我想返回一个像上例中的
{TYPE1= (0.66), TYPE2 = (0.875)}
这样的地图。我不允许使用 for 循环或 forEach
函数。
如果您使用的是 Java 12+,您可以使用
Collectors.teeing
来解决此问题。
我们将两个Collectors传递给
Collectors.teeing
;第一个对函数 a()
的返回值求和,第二个对函数 b()
的返回值求和。在 teeing 的 merger
函数中,我们将求和值相除。
public static Map<String, Double> myFunction(Stream<TestRecord> testRecordStream) {
return testRecordStream
.collect(Collectors.groupingBy(TestRecord::type,
Collectors.teeing(
Collectors.summingDouble(TestRecord::a),
Collectors.summingDouble(TestRecord::b),
(a, b) -> a / b)
));
}
如果您正在使用 Java 版本的 < 12, then you can use reduction 机制来减少(这里是总和)给定类型的值。但这需要一个简单的辅助类。
private class Pair {
private final int l;
private final int r;
//Constructors, getters skipped
}
reducing收集器在collectingAndThen收集器中使用。
new Pair(0, 0)
)。TestRecord
的实例映射到 Pair
。l
和 r
)。最后,在归约之后,我们将得到一个
Pair
实例,其 l
等于所有 a()
函数值的总和,而 r
是所有 b()
函数值的总和(对于给定的 type
)。我们在 collectingAndThen
收集器的 finisher中划分这两个。
public static Map<String, Double> myFunction(Stream<TestRecord> testRecordStream) {
return testRecordStream
.collect(Collectors.groupingBy(TestRecord::type,
Collectors.collectingAndThen(
Collectors.reducing(new Pair(0, 0),
testRecord -> new Pair(testRecord.a(), testRecord.b()),
(p1, p2) -> new Pair(p1.l + p2.l, p1.r + p2.r)),
pair -> (double) pair.l / pair.r
)));
}