[英]Java Lambda expression to avoid multiple iterations
Folks, 伙计们,
Consider the following example, given a list of Trade objects my code needs to return an array containing trade volume for 24 hours, 7 days, 30 days and all times. 考虑以下示例,给定一个Trade对象列表,我的代码需要返回一个包含交易量24小时,7天,30天和所有时间的数组。
Using plain old iterator this requires only a single iteration over the collection. 使用普通的旧迭代器,这只需要对集合进行一次迭代。
I'm trying to do the same using a Java 8 streams and Lambda expressions. 我正在尝试使用Java 8流和Lambda表达式来做同样的事情。 I came up with this code, which looks elegant, works fine, but requires 4 iterations over the list:
我提出了这个代码,它看起来很优雅,工作正常,但需要在列表上进行4次迭代:
public static final int DAY = 24 * 60 * 60;
public double[] getTradeVolumes(List<Trade> trades, int timeStamp) {
double volume = trades.stream().mapToDouble(Trade::getVolume).sum();
double volume30d = trades.stream().filter(trade -> trade.getTimestamp() + 30 * DAY > timeStamp).mapToDouble(Trade::getVolume).sum();
double volume7d = trades.stream().filter(trade -> trade.getTimestamp() + 7 * DAY > timeStamp).mapToDouble(Trade::getVolume).sum();
double volume24h = trades.stream().filter(trade -> trade.getTimestamp() + DAY > timeStamp).mapToDouble(Trade::getVolume).sum();
return new double[]{volume24h, volume7d, volume30d, volume};
}
How can I achieve the same using only a single iteration over the list ? 如何在列表中仅使用一次迭代来实现相同的目标?
This problem is similar to the "summary statistics" collector. 此问题类似于“摘要统计信息”收集器。 Take a look at the
IntSummaryStatistics
class: 看看
IntSummaryStatistics
类:
public class IntSummaryStatistics implements IntConsumer {
private long count;
private long sum;
...
public void accept(int value) {
++count;
sum += value;
min = Math.min(min, value);
max = Math.max(max, value);
}
...
} }
It is designed to work with collect()
; 它旨在与
collect()
; here's the implementation of IntStream.summaryStatistics()
这是
IntStream.summaryStatistics()
的实现
public final IntSummaryStatistics summaryStatistics() {
return collect(IntSummaryStatistics::new, IntSummaryStatistics::accept,
IntSummaryStatistics::combine);
}
The benefit of writing a Collector
like this is then your custom aggregation can run in parallel. 编写像这样的
Collector
的好处是您的自定义聚合可以并行运行。
Thanks Brian, I ended up implementing the code below, it's not as simple as I hoped but at least it iterates only once, its parallel ready and it passes my unit tests. 谢谢Brian,我最终实现了下面的代码,它并不像我希望的那样简单,但至少它只迭代一次,它的并行就绪,它通过我的单元测试。 Any improvements ideas are welcomed.
欢迎任何改进的想法。
public double[] getTradeVolumes(List<Trade> trades, int timeStamp) {
TradeVolume tradeVolume = trades.stream().collect(
() -> new TradeVolume(timeStamp),
TradeVolume::accept,
TradeVolume::combine);
return tradeVolume.getVolume();
}
public static final int DAY = 24 * 60 * 60;
static class TradeVolume {
private int timeStamp;
private double[] volume = new double[4];
TradeVolume(int timeStamp) {
this.timeStamp = timeStamp;
}
public void accept(Trade trade) {
long tradeTime = trade.getTimestamp();
double tradeVolume = trade.getVolume();
volume[3] += tradeVolume;
if (!(tradeTime + 30 * DAY > timeStamp)) {
return;
}
volume[2] += tradeVolume;
if (!(tradeTime + 7 * DAY > timeStamp)) {
return;
}
volume[1] += tradeVolume;
if (!(tradeTime + DAY > timeStamp)) {
return;
}
volume[0] += tradeVolume;
}
public void combine(TradeVolume tradeVolume) {
volume[0] += tradeVolume.volume[0];
volume[1] += tradeVolume.volume[1];
volume[2] += tradeVolume.volume[2];
volume[3] += tradeVolume.volume[3];
}
public double[] getVolume() {
return volume;
}
}
It might be possible to use a Collectors.groupingBy
method to partition the data however the equation would be complicated and not intent revealing. 也许可以使用
Collectors.groupingBy
方法对数据进行分区,但是方程式会很复杂而且没有意图揭示。
Since getTimestamp()
is an expensive operation, it is probably best to keep it as a pre-Java 8 iteration so you only have to calculate the value once per Trade
. 由于
getTimestamp()
是一项昂贵的操作,因此最好将其保留为Java 8之前的迭代,因此您只需按每次Trade
计算一次值。
Just because Java 8 adds shiny new tools, don't try to turn it into a hammer to hammer in all nails. 仅仅因为Java 8添加了闪亮的新工具,不要试图将它变成锤子来锤击所有钉子。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.