如何使用单个流操作从对象获取多个值? [英] How to get multiple values from an object using a single stream operation?
问题描述
我想确定显示点集合所需的最小区域。简单的方法是循环遍历集合,如下所示:
I want to determine the minimum area required to display a collection of points. The easy way is to loop through the collection like this:
int minX = Integer.MAX_VALUE;
int maxX = Integer.MIN_VALUE;
int minY = Integer.MAX_VALUE;
int maxY = Integer.MIN_VALUE;
for (Point point: points) {
if (point.x < minX) {
minX = point.x;
}
if (point.x > maxX) {
maxX = point.x;
}
if (point.y < minY) {
minY = point.y;
}
if (point.y > maxY) {
maxY = point.y;
}
}
我开始了解溪流。为此,您可以执行以下操作:
I am getting to know streams. To do the same, you can do the following:
int minX = points.stream().mapToInt(point -> point.x).min().orElse(-1);
int maxX = points.stream().mapToInt(point -> point.x).max().orElse(-1);
int minY = points.stream().mapToInt(point -> point.y).min().orElse(-1);
int maxY = points.stream().mapToInt(point -> point.y).max().orElse(-1);
两者都给出相同的结果。然而,尽管流方法很优雅,但速度要慢得多(如预期的那样)。
Both give the same result. However, although the streams approach is elegant, it is much slower (as expected).
有没有办法获得 minX
, maxX
, minY
和 maxY
in a单流操作?
Is there a way to get minX
, maxX
, minY
and maxY
in a single stream operation?
推荐答案
与 IntSummaryStatistics
,创建一个班级 PointStatistics
,它会收集您需要的信息。它定义了两种方法:一种用于记录来自 Point
的值,一种用于组合两个 Statistics
。
By analogy with IntSummaryStatistics
, create a class PointStatistics
which collects the information you need. It defines two methods: one for recording values from a Point
, one for combining two Statistics
.
class PointStatistics {
private int minX = Integer.MAX_VALUE;
private int maxX = Integer.MIN_VALUE;
private int minY = Integer.MAX_VALUE;
private int maxY = Integer.MIN_VALUE;
public void accept(Point p) {
minX = Math.min(minX, p.x);
maxX = Math.max(maxX, p.x);
minY = Math.min(minY, p.y);
maxY = Math.max(minY, p.y);
}
public void combine(PointStatistics o) {
minX = Math.min(minX, o.minX);
maxX = Math.max(maxX, o.maxX);
minY = Math.min(minY, o.minY);
maxY = Math.max(maxY, o.maxY);
}
// getters
}
然后,您可以将 Stream< Point>
收集到 PointStatistics
。
Then you can collect a Stream<Point>
into a PointStatistics
.
class Program {
public static void main(String[] args) {
List<Point> points = new ArrayList<>();
// populate 'points'
PointStatistics statistics = points
.stream()
.collect(PointStatistics::new, PointStatistics::accept, PointStatistics::combine);
}
}
更新
我对OP提出的结论感到非常困惑,所以我决定写 JMH 基准。
I was completely baffled by the conclusion drawn by OP, so I decided to write JMH benchmarks.
基准设置:
# JMH version: 1.21
# VM version: JDK 1.8.0_171, Java HotSpot(TM) 64-Bit Server VM, 25.171-b11
# Warmup: 1 iterations, 10 s each
# Measurement: 10 iterations, 10 s each
# Timeout: 10 min per iteration
# Benchmark mode: Average time, time/op
对于每次迭代,我都是生成随机 Point
s的共享列表( new Point(random.nextInt(),random.nextInt())
)大小100K,1M,10M。
For each iteration, I was generating a shared list of random Point
s (new Point(random.nextInt(), random.nextInt())
) of size 100K, 1M, 10M.
结果是
100K
Benchmark Mode Cnt Score Error Units
customCollector avgt 10 6.760 ± 0.789 ms/op
forEach avgt 10 0.255 ± 0.033 ms/op
fourStreams avgt 10 5.115 ± 1.149 ms/op
statistics avgt 10 0.887 ± 0.114 ms/op
twoStreams avgt 10 2.869 ± 0.567 ms/op
1M
Benchmark Mode Cnt Score Error Units
customCollector avgt 10 68.117 ± 4.822 ms/op
forEach avgt 10 3.939 ± 0.559 ms/op
fourStreams avgt 10 57.800 ± 4.817 ms/op
statistics avgt 10 9.904 ± 1.048 ms/op
twoStreams avgt 10 32.303 ± 2.498 ms/op
10M
Benchmark Mode Cnt Score Error Units
customCollector avgt 10 714.016 ± 151.558 ms/op
forEach avgt 10 54.334 ± 9.820 ms/op
fourStreams avgt 10 699.599 ± 138.332 ms/op
statistics avgt 10 148.649 ± 26.248 ms/op
twoStreams avgt 10 429.050 ± 72.879 ms/op
这篇关于如何使用单个流操作从对象获取多个值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!