【问题标题】:java reduce on the array in the classjava减少类中的数组
【发布时间】:2016-01-20 13:43:27
【问题描述】:

我尝试使用 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 循环中,我想对 Link 类中每个数组项的值求和。但是,我有以下问题:

在封闭范围内定义的局部变量必须是最终的或有效的最终

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

或者有没有更好的总结价值? (没有 for 循环?)

【问题讨论】:

  • 这里可能是变量i。尝试在循环中定义最终副本,例如final int k = i 然后在 lambda 中使用 getFlows()[k]
  • 也使用后缀自增运算符:i++
  • 前缀和for循环中的后缀一样好。

标签: java arrays java-8 java-stream final


【解决方案1】:

你走错路了:你不应该有一个外部的for 循环,而是处理流管道中的所有内容。

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

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

为此,我们必须依赖使用 Stream 而非索引,因为没有用于将两个 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]

【讨论】:

  • 顺便说一句,您需要以某种方式确保所有数组的长度相同。您可以在 Link 的构造函数中检查长度。
【解决方案2】:

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

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

这里i实际上是最终的。

【讨论】:

    【解决方案3】:

    如果您添加 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()));
        }
    

    【讨论】:

    • 谢谢。这里的语法比较简单。
    猜你喜欢
    • 2017-08-22
    • 2013-12-23
    • 1970-01-01
    • 2021-09-28
    • 2021-06-13
    • 1970-01-01
    • 2023-02-24
    • 2018-02-16
    • 2020-12-30
    相关资源
    最近更新 更多