我有两份清单如下:
List<Double> margins = Arrays.asList(1.0,2.0,3.0,4.0,5.0);
List<Integer> quantity = Arrays.asList(1,2,3,4,5);
我想在它们之间做元素乘法,我知道我可以用标准的for循环来实现它,但是我想知道我们是否可以通过Stream来实现同样的过程,使这个过程更快,更少的资源?
类似于Python对NumPy数组所做的事情;与其制作一个for
循环,而是将矢量化,从而使其更快。
发布于 2022-08-10 08:52:48
,类似于Python对numpy数组所做的事情;与其做一个
for
循环,不如将矢量化,这使得它更快。
如果您对感兴趣,那么Stream就是,而不是您要寻找的。
因为Java16我们将作为一个 (这意味着它不是API的最终状态,而是用于测试和收集反馈,您不应该在生产中使用它)。
为了在Java中使用孵化器特性,您需要做一些额外的工作来从导入的孵化器模块获取文件。
确保从包jdk.incubator.vector
导入类的方法之一是创建一个模块,以显式指定它需要这个包。
考虑一个具有以下文件夹结构的简单测试项目:
- [src]
- [main]
- [java]
- module-info.java
- [vectorization.test]
- Main.java
- resources
// other things
module-info.java
--这里我们请求Vector的文件:
module vectorization.test {
requires jdk.incubator.vector;
}
Main.java
package vectorization.test;
import jdk.incubator.vector.DoubleVector;
import jdk.incubator.vector.VectorSpecies;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
double[] margins = {1.0, 2.0, 3.0, 4.0, 5.0};
double[] quantity = {1, 2, 3, 4, 5};
double[] result = new double[margins.length];
multiply(margins, quantity, result);
System.out.println(Arrays.toString(result));
}
public static final VectorSpecies<Double> SPECIES = DoubleVector.SPECIES_PREFERRED;
public static void multiply(double[] margins, double[] quantity, double[] result) {
int i = 0;
for (; i < SPECIES.loopBound(margins.length); i += SPECIES.length()) {
DoubleVector marginsVector = DoubleVector.fromArray(SPECIES, margins, i);
DoubleVector quantityVector = DoubleVector.fromArray(SPECIES, quantity, i);
DoubleVector resultVector = marginsVector.mul(quantityVector);
resultVector.intoArray(result, i);
}
for (; i < margins.length; i++) {
result[i] = margins[i] * quantity[i];
}
}
}
输出:
[1.0, 4.0, 9.0, 16.0, 25.0]
有关Vector的更多信息,请查看。
说到流,它们并不比普通循环(如果是顺序流)更具有性能,实际上它们是较慢的,因为流需要创建额外的对象来执行迭代、进行转换和积累结果。这里没有魔法。
并行流可能更快,但它是一个应该谨慎使用的工具,因为您也可能得到相反的效果。您需要您的任务是可并行的,您的线程应该有空闲的CPU内核来完成这项工作,并且数据量应该很大,以使并行流的使用变得合理(并且仍然需要测量性能以确定它在您的情况下是否起作用)。
在Java中引入函数式编程特性的主要目标之一是提供一种简洁和可读的方法来构造代码。
例如,如何使用Arrays.setAll()
填充生成的产品数组
Arrays.setAll(result, i -> margins[i] * quantity[i]);
发布于 2022-08-09 18:01:52
您可以通过流将数组的元素相乘,但它不会比传统的循环更有效。然而,对于如此小的数据集,开销非常小,不会产生任何影响。
下面是通过流实现的方法。基本上,您可以使用IntStream
类将两个列表从0迭代到最小列表的大小(不包括)。然后,将每个int索引映射到一个双重对象,该对象表示margins
列表的第一个元素的乘积和quantity
列表的第一个元素,最后将结果收集到一个List<Double>
中。
List<Double> margins = Arrays.asList(1.0, 2.0, 3.0, 4.0, 5.0);
List<Integer> quantity = Arrays.asList(1, 2, 3, 4, 5);
List<Double> res = IntStream.range(0, Math.min(margins.size(), quantity.size()))
.mapToObj(i -> margins.get(i) * quantity.get(i))
.collect(Collectors.toList());
https://stackoverflow.com/questions/73296071
复制相似问题