简体   繁体   English

使用Java 8迭代2D数组

[英]Iterating a 2D Array using Java 8

This is an implementation of the 0-1 Knapsack Problem. 这是0-1背包问题的实现。 The problem statement goes like this, 问题陈述是这样的,

You're given two arrays, one containing the weights of a set of items and the other containing values for the respective weights. 您将获得两个数组,一个数组包含一组项目的权重,另一个数组包含相应权重的值。 You're provided a max weight. 您已获得最大体重。 Within the constraint of staying under the max weight, determine the maximum value that you can obtain by selecting or not selecting the set of items. 在不超过最大重量的约束范围内,确定通过选择或不选择一组项目可获得的最大值。 The values and the weight list will always be of the same size. 值和重量列表将始终具有相同的大小。

This is my solution, which generally works fine(not on edge cases). 这是我的解决方案,通常可以正常工作(不适用于边缘情况)。

  public static int getCombination(int[] weights, int[] values, int maxWeight){

        int[][] memo = new int[weights.length][maxWeight + 1];
        for (int i = 0; i < memo.length; i++) {
          for(int j=0; j < memo[i].length; j++){
            if(j == 0){
              memo[i][j] = 0;
            }else if(weights[i] > j){
              if(i == 0) memo[i][j] = 0;
              else memo[i][j] = memo[i-1][j];
            }else{
              if(i == 0){
                memo[i][j] = values[i];
              }
              else{
                memo[i][j] = Integer.max((values[i] + memo[i-1][j- weights[i]]), memo[i-1][j]);
              }
            }
          }
        }
        return memo[weights.length -1][maxWeight];
      }

Now I want to re-write this complete logic in a declarative manner using Java 8 Streams and lambdas. 现在,我想使用Java 8 Streams和lambda以声明的方式重新编写此完整逻辑。 Can someone help me with that. 有人可以帮我吗。

Since your for loop based solution is completely fine, streams do not add much value here if you only convert the for loops to forEach streams. 由于基于for循环的解决方案完全可以解决,因此,如果仅将for循环转换为forEach流,则流不会在此处增加太多价值。

You get more out of using streams, if you use IntStream and the toArray method, because you can concentrate on calculating the value based on row and column index, and not care about filling it into the array. 如果使用IntStreamtoArray方法,则可以从使用流中获得更多IntStream ,因为您可以专注于基于行和列索引来计算值,而不用担心将其填充到数组中。

int[][] memo = IntStream.range(0, rows)
                        .mapToObj(r -> IntStream.range(0, cols)
                                                .map(c -> computeValue(r, c))
                                                .toArray())
                        .toArray(int[rows][cols]::new);

Here, we create an array for each row, and then put those into a 2D-array at the end. 在这里,我们为每一行创建一个数组,然后将它们放在最后的2D数组中。 As you can see, the toArray() methods take care of filling the arrays. 如您所见, toArray()方法负责填充数组。


Actually, now that I looked at your method to calculate the values more closely, I realize that streams might be difficult if not impossible to use in this case. 实际上,既然我研究了您的方法来更紧密地计算值,我意识到在这种情况下即使不是不可能使用流也可能很困难。 The problem is that you need values from previous columns and rows to calculate the current value. 问题是您需要以前的列和行中的值才能计算当前值。 This is not possible in my solution precisely because we only create the arrays at the end. 在我的解决方案中这是不可能的,因为我们只在最后创建数组。 More specifically, my approach is stateless, ie you do not remember the result of previous iterations. 更具体地说,我的方法是无状态的,即您不记得先前迭代的结果。

You could see if you can use Stream.reduce() to achieve your goal instead. 您可以看到是否可以使用Stream.reduce()来实现目标。

BTW, your approach is fine. 顺便说一句,你的方法很好。 If you don't want to parallelize this, you are good to go. 如果您不想并行化它,那很好。

Here's a possible starting point to create the indices into your array: 这是在数组中创建索引的可能起点:

        int rows = 3;
        int cols = 4;
        int[][] memo = new int[rows][cols];
        IntStream.range(0, rows * cols).forEach(n -> {
            int i = n / cols;
            int j = n % cols;

            System.out.println("(" + i + "," + j + ")");
        });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM