我有MetricGroup
的信息流,其中:
public class MetricGroup {
private int uploadedDocs;
private long uploadedKbs;
// getters and setters
}
我需要将所有指标汇总为一个指标。我的意思是,我需要将所有metric.uploadedDocs
添加到sumMetric.uploadedDocs
中,并将metric.uploadedKds
添加到sumMetric.uploadedKbs
中。
我发现我需要某种reduce
Stream.of(new MetricGroup(1,100), new MetricGroup(1,200))
.reduce(????);
有什么想法吗?
答案 0 :(得分:7)
您可以使用reduce
的此重载:
T reduce(T identity,
BinaryOperator<T> accumulator)
像这样:
.reduce(new MetricGroup(0, 0),
(x, y) -> new MetricGroup(
x.getUploadedDocs() + y.getUploadedDocs()
x.getUploadedKbs() + y.getUploadedKbs()
)
)
您还可以使用collect
方法:
private static MetricGroup combine(MetricGroup x, MetricGroup y) {
x.setUploadedDocs(x.getUploadedDocs() + y.getUploadedDocs());
x.setUploadedKbs(x.getUploadedKbs() + y.getUploadedKbs());
return x;
}
// ....
.collect(() -> new MetricGroup(0, 0),
YourClass::combine,
YourClass::combine
)
答案 1 :(得分:3)
为避免在MetricGroup
调用过程中创建多个reduce
对象,可以进行两个单独的调用来分别对UploadedDocs
和UploadedKbs
求和,然后构造代表结果的新MetricGroup
。
int uploadedDocsSum = source.stream().mapToInt(MetricGroup::getUploadedDocs).sum();
long uploadedKbsSum = source.stream().mapToLong(MetricGroup::getUploadedKbs).sum();
MetricGroup result = new MetricGroup(uploadedDocsSum, uploadedKbsSum);
也可以说更具可读性...
答案 2 :(得分:2)
只需传入一个lambda(将操作现有的MetricGroup)
Stream.of(new MetricGroup(1, 100), new MetricGroup(1, 200))
.reduce((a, b) -> {
a.setUploadedDocs(a.getUploadedDocs() + b.getUploadedDocs());
a.setUploadedKbs(a.getUploadedKbs() + b.getUploadedKbs());
return a;
});
// Optional[F.MetricGroup(uploadedDocs=2, uploadedKbs=300)]
或者,要真正获得一个新的MetricGroup(无需操纵现有的MetricGroup)
Stream.of(new MetricGroup(1, 100), new MetricGroup(1, 200))
.reduce((a, b) -> new MetricGroup(a.getUploadedDocs() + b.getUploadedDocs(), a.getUploadedKbs() + b.getUploadedKbs()));
答案 3 :(得分:2)
与java流一样,您实际上不必使用它们。我建议创建一个简单的减少辅助方法:
public static MetricGroup reduce(Iterable<? extends MetricGroup> metrics){
int uploadedDocs = 0;
long uploadedKbs = 0L;
for(MetricGroup metric : metrics){
uploadedDocs += metric.getUploadedDocs();
uploadedKbs += metric.getUploadedKbs();
}
return new MetricGroup(uploadedDocs, uploadedKbs);
}
如果您不能更改以流开头,则仍然可以使用上述方法,只需传递对Stream.iterator()
方法的引用即可:
MetricGroup reduced = reduce(stream::iterator);
答案 4 :(得分:1)
如果要使用归约法,建议将MetricGroup
设为值类型,方法是将字段定为最终字段,添加零,然后用组合方法替换设置器。
public class MetricGroup {
private final int uploadedDocs;
private final long uploadedKbs;
// obvious constructor
// getters
public static final ZERO = new MetricGroup(0, 0);
public MetricGroup add(MetricGroup a, MetricGroup b) {
return new MetricGroup(a.uploadedDocs + b.upLoadedDocs,
a.uploadedKbs + b.uploadedKbs);
}
public MetricGroup uploadOneDoc(long kbs) {
return new MetricGroup(uploadedDocs + 1, uploadedKbs + kbs);
}
}
这将使您很好地执行流操作:
MetricGroup sum = metricGroups.stream()
.reduce(MetricGroup.ZERO, MetricGroup::add);