java 减少 class 中的数组

java reduce on the array in the class

我尝试使用 reduce 对 HashMap 值求和。

public class Link 
{
    private double[] flows;
    public Link(double[] f) {
        setFlows(f);
    }
    public double[] getFlows() {
        return flows;
    }
    public void setFlows(double[] flows) {
        this.flows = flows;
    }

    public static void main(String argv[])
    {
         // TEST for reduce on HashMap
         HashMap<Integer, Link> id1 = new HashMap<Integer, Link>();
         id1.put(1, new Link(new double[]{10,1,30}));
         id1.put(2, new Link(new double[]{20,2,3}));
         id1.put(3, new Link(new double[]{30,2,3}));
         id1.put(4, new Link(new double[]{40,2,30}));

         double[] my_sum = new double[3];
         for (int i=0; i < 3; ++i)
         {
              my_sum[i] = id1.entrySet().stream().mapToDouble(e->e.getValue().getFlows()[i]).sum();
         }
         assert(my_sum[0] == 100);
         assert(my_sum[1] == 7);
         assert(my_sum[2] == 66);
    }
}

在for循环中,我想对Linkclass中每个数组项的值求和。但是,我遇到以下问题:

local variable defined in enclosing scope must be final or effectively final

基本上我不想将final变量定义为class成员,如何解决?

或者有没有更好的求和值? (没有 for 循环?)

你的做法是错误的:你不应该有一个外部 for 循环,而是处理 Stream 管道内的所有内容。

您可以通过 storing the variable i into a final local variable 使其工作。

在下面的代码中,只保留地图的值(因为我们对键不感兴趣)。然后将每个值映射到它们的流。最后,通过首先创建一个包含 3 个元素的数组(初始化为 0)然后通过对同一索引处的值求和将两个双精度数组组合成一个结果数组来减少结果 Stream<double[]>

为此,我们必须依靠在索引上使用 Stream,因为没有 built-in 将两个 Stream 压缩在一起的工具。

double[] my_sum = 
    id1.values().stream()
                .map(Link::getFlows)
                .reduce(
                    new double[3],
                    (v1, v2) -> IntStream.range(0, v2.length).mapToDouble(i -> v1[i] + v2[i]).toArray()
                );

System.out.println(Arrays.toString(my_sum)); // prints [100.0, 7.0, 66.0]

如果您添加 add 方法(不幸的是使 Link 可变),您也可以使用 Link 求和。

    // Makes it mutable - will try immutable later
    public void add(Link other) {
        for (int i = 0; i < flows.length; i++) {
            flows[i] += other.flows[i];
        }
    }

    public static void main(String argv[]) {
        // TEST for reduce on HashMap
        HashMap<Integer, Link> id1 = new HashMap<>();
        id1.put(1, new Link(new double[]{10, 1, 30}));
        id1.put(2, new Link(new double[]{20, 2, 3}));
        id1.put(3, new Link(new double[]{30, 2, 3}));
        id1.put(4, new Link(new double[]{40, 2, 30}));

        Link sum = new Link(new double[3]);
        id1.entrySet().stream().forEach(l -> sum.add(l.getValue()));
    }

对我来说更好的替代方法是使用 Arrays.setAll:

double[] my_sum = new double[3];
Arrays.setAll(my_sum, 
  i -> id1.entrySet().stream().mapToDouble(e->e.getValue().getFlows()[i]).sum());

此处 i 实际上是最终的。