以下是如何在不迭代数组索引并尝试使用流模仿 for
-loop 的方法。
我们还可以一路上获取实际的最小值。
为此,我们可以使用 DoubleStream.collect()
,它需要三个参数:
Supplier<R>
supplier - 提供一个可变对象,该对象将用作数据的容器;
ObjDoubleConsumer<R>
accumulator - 确定如何在由supplier提供的可变收集器中累积流元素;
BiConsumer<R,R>
combiner - 在并行执行流时组合部分结果。
作为一个可变容器,供应商可以提供
double[]
数组 (如果您查看旨在累加原始值的收集器的源代码,例如
summingInt()
、
summingDouble()
等,您可能会发现一些相似之处)。
double[] arr = {263.5, 393.75, 5.0, 289.75};
double[] min = Arrays.stream(arr)
.collect(
() -> new double[]{0, -1, 0},
(double[] res, double next) -> {
res[2]++;
if (res[1] == -1 || res[0] > next) {
res[0] = next;
res[1] = res[2] - 1;
}
},
(left, right) -> {
if (left[0] > right[0]) {
left[0] = right[0];
left[1] = left[2] + right[1];
}
left[2] += right[2];
}
);
System.out.printf("Min value is %s at index: %d", min[0], (int) min[1]);
输出:
Min value is 5.0 at index: 2
上面显示的确定最小值和跟踪已消耗元素数量的逻辑可以封装到一个类
中(如@Holger所建议的),该类将用作累加类型而不是数组。
为了方便起见,我实现了{{link1:DoubleConsumer
}}接口,它的方法accept()
将用于实现累加器。方法merge()
将用于组合器。
public static class MinValueAndIndex implements DoubleConsumer {
private int totalCount;
private int index;
private double min;
@Override
public void accept(double value) {
if (totalCount == 0 || value < min) {
min = value;
index = totalCount;
}
totalCount++;
}
public void merge(MinValueAndIndex other) {
if (min > other.min) {
min = other.min;
index = totalCount + other.index;
}
totalCount += other.totalCount;
}
}
流应该是这样的:
double[] arr = {263.5, 393.75, 5.0, 289.75};
MinValueAndIndex valueIndex = Arrays.stream(arr)
.collect(
MinValueAndIndex::new,
MinValueAndIndex::accept,
MinValueAndIndex::merge
);
System.out.printf("Min value is %s at index: %d", valueIndex.getMin(), valueIndex.getIndex());
输出:
Min value is 5.0 at index: 2