假设我有两个double数组。 我一直在尝试使用Java 8中的Stream。我想我已经理解了主要的想法 但后来我意识到我不确定如何同时操纵两个Streams。
例如,我想计算两个数组的协方差。
public class foo {
public static double mean(double[] xs) {
return Arrays.stream(xs).average().getAsDouble();
}
public static void main(String[] args) {
double[] xs = {1, 2, 3, 4, 5, 6, 7, 8, 9};
double[] ys = {1517.93, 1757.78, 1981.1, 2215.73, 2942.66, 3558.32, 4063.91, 4521.16, 5101.76, 5234.12};
System.out.println("Mean of xs: " + mean(xs));
double xs_sumDeviation = Arrays.stream(xs)
.boxed()
.mapToDouble(d -> d.doubleValue() - mean(xs))
.sum();
// Covariance
double covXY = Arrays.stream(xs, ys)
.mapToDouble(x,y -> {
double numerator = (x-mean(xs)* (y-mean(ys);
double denominator = Math.sqrt((x-mean(xs)* (x-mean(xs));
return numerator / denominator;
})
.sum();
}
}
感谢您的建议。
尝试1。
public static double covariance(double[] xs, double[] ys) {
double xmean = mean(xs);
double ymean = mean(ys);
double numerator = IntStream.range(0, Math.min(xs.length, ys.length))
.parallel()
.mapToDouble(i -> (xs[i] - xmean) * (ys[i] - ymean))
.sum();
double denominator = Math.sqrt(IntStream.range(0, xs.length)
.parallel()
.mapToDouble(i -> (xs[i] - xmean) * (xs[i] - xmean))
.sum());
return numerator / denominator;
答案 0 :(得分:5)
在其他编程语言中,有某种 zip 函数,它需要几个 iterables ,并返回一个 iterator ,它聚合来自的元素每个 iterables 。例如,参见Python库中的函数zip。
尽管可以在Java中创建类似的函数,但很难以这种方式实现它,它支持高效的并行执行。但是,Java中有一种常用的模式,有点不同。在您的情况下,它可能如下所示:
public static double covariance(double[] xs, double[] ys) {
double xmean = mean(xs);
double ymean = mean(ys);
return IntStream.range(0, Math.min(xs.length, ys.length))
.parallel()
.mapToDouble(i -> {
double numerator = (xs[i] - xmean) * (ys[i] - ymean);
double denominator = ...;
return numerator / denominator;
})
.sum();
}
您可以使用所有索引创建IntStream
,而不是组合两个流,并通过索引访问不同集合的元素。只要集合支持随机访问操作,它就能很好地工作。
答案 1 :(得分:3)
其他FP语言具有zip
操作,它从两个元素流中生成对流。这还没有在Java中提供。
但是,对于数组,您可以轻松地创建数组索引的流,并让您的函数关闭数组,并通过index参数访问它们。
我也应警告你,在这一行
.mapToDouble(d -> d.doubleValue() - mean(xs))
您正在使程序复杂度为O(n 2 ),因为在每一步都会重新计算mean
。你应该预先计算并关闭lambda中的结果。