【问题标题】:How to initialize two dimensional array in java 8如何在 java 8 中初始化二维数组
【发布时间】:2018-08-27 23:55:03
【问题描述】:

在 Java 8 版本之前,我们可以使用如下的 for 循环来初始化一个二维数组。如何使用 lambda 表达式在 JDK 1.8 中执行以下操作?

int[][] board = new int[3][3];
int v = 1;
for (int i = 0; i < board.length; i++) {

    for (int j = 0; j < 3; j++) {

        board[i][j] = v;
        v++;
        System.out.println(v);
    }
}
System.out.println(Arrays.deepToString(board));

基本上,我正在寻找一个像下面这样的数组

[[1,6],[2,7],[3,8],[4,9]]

【问题讨论】:

  • int[][] board = IntStream.range(0, 3).mapToObj(i -&gt; IntStream.range(0, 3).map(j -&gt; i * 3 + j + 1).toArray()).toArray(int[][]::new);
  • 谢谢@shmosel,我想要一个如下的数组 [[1,6],[2,7],[3,8],[4,9]]
  • 传统的for循环具有更好的可读性和更高的效率,尤其是在处理原始类型时。我建议使用传统的for 循环,除非您另有要求。
  • 5 是故意遗漏还是忘记了?
  • 您的循环不会产生这种情况。

标签: java arrays java-8 java-stream


【解决方案1】:

我强烈建议您坚持使用for-loop 来初始化具有原始值的数组。在多维数组的情况下,我的建议更强。

但是,方法如下:

int a = 4;               // Number of outer array elements
int b = 2;               // Number of inner array elements

int[][] board = IntStream
    .range(0, a)                                               // iterate 0..3
    .mapToObj(i -> IntStream.range(0, b)                       // for each iteratoe 0..1
                            .map(j -> 1 + (i + (a + 1) * j))   // calculate the value
                            .toArray())                        // compose the inner array
    .toArray(int[][]::new);                                    // compose the outer array

请注意,IntStream 能够创建原始数组,因为它是原始 int 值元素的序列。它的方法IntStream::toArray reutrns int[]

外部数组的组成有点棘手,因为int[] 不再是原始值,而是数组本身。需要使用将int 映射到对象的方法IntStream::mapToObj - 然后返回Stream&lt;int[]&gt; 并且必须使用方法Stream::toArray(IntFunction&lt;A[]&gt; generator) 转换为带参数的数组,因为您无法将Object[] 转换为@ 987654337@.

传递的参数很简单。 int[][]::newi -&gt; new int[a][b] 没有什么不同。

【讨论】:

    【解决方案2】:

    使用IntStream。这将创建一个连续的整数流,从 0 包含到 n 不包含。所以对于一个 3 x 3 矩阵,IntStream0, 1, 2。 为从0 到列数的外部流中的每个整数创建另一个IntStream - 也是3。

    您不能在流中增加v,因为它必须是“有效最终的”。相反,我们使用公式board[j][i] = 1 + (j + m * i),如果您要将板展平为单个数组(一维矩阵),这实际上类似于计算值的索引。

    import java.util.stream.IntStream;
    import java.util.Arrays;
    
    class J {
    
      public static void main(String[] args) {
    
        int n = 4;
        int m = 2;
    
        // n x m matrix
        int[][] board = new int[n][m];
    
        // Cols (m)
        IntStream.range(0, m).forEach( i -> {
    
          // Rows (n)
          IntStream.range(0, n).forEach( j -> {
    
            // Multiply i by row count
            // to account for the row we are in
            board[j][i] = 1 + (j + n * i);
          });
    
    
        });
    
        System.out.println(Arrays.deepToString(board));
    
      }
    
    }
    

    输出:

    [[1, 5], [2, 6], [3, 7], [4, 8]]
    

    注意:仅仅因为流允许您编写更简洁、类似函数式编程的语法,因此通常会产生相关的性能损失。它强调了这样一个想法,“为什么要修复没有损坏的东西?”。对于 3 x 3 板,您可能看不出有什么不同。但是,如果您的电路板更大,考虑到所有创建的对象和在场景后面使用的额外空间,它可能不会证明自己是值得的。有时,一个简单的 for 循环(尤其是在处理数组时)会更好。

    记住,简单是关键。

    【讨论】:

    • 谢谢。我想要 [[1,6],[2,7],[3,8],[4,9]]
    • @sc1234 5 呢?您在序列中跳过了 5 个。您需要制作矩阵4 x 2(4 行,每行 2 列)您将板指定为3 x 3。这意味着您有 3 行 3 列。您的预期输出与您提供给我们的输入不一致。
    • @sc1234 已编辑
    【解决方案3】:

    这是一个“嵌套循环”的流解决方案,看起来很像。

    1. 获取从0到N的数字序列(不包括上限-> N = board.length;
    2. 获取从0到M的数字序列(不包括上限-> M = board[i].length;
    3. 对于每一对 (i, j),使用 func (i + j * step + 1) 设置 board[i][j] 的值,其中 step 定义为 5。

    int[][] 板的输出 = new int[4][2];

    [[1, 6], [2, 7], [3, 8], [4, 9]]

    int[][] 板的输出 = new int[4][3];

    [[1, 6, 11], [2, 7, 12], [3, 8, 13], [4, 9, 14]]

    int step = 5;
    
    IntStream.range(0, board.length).forEach(i ->
        IntStream.range(0, board[i].length).forEach(j ->
            board[i][j] = i + j * step + 1
        )
    );
    

    【讨论】:

      【解决方案4】:

      您可以结合使用IntStream 方法rangeiterate

      int width = 4, height = 2;
      
      IntStream.rangeClosed(1, width)
               .mapToObj(column -> IntStream.iterate(column, v -> v + width)
                                            .limit(height)
                                            .toArray())
               .toArray(int[][]::new);
      

      通过将iterate 用于内部循环并使用rangeClosed(1, width) 代替range(0, width),我们可以稍微简化计算。使用toArray 消除了自己创建和修改数组的需要,并且可以启用并行处理。

      重要的是要正确使用流,以使它们不仅仅是奇怪的寻找循环。仅仅用 range(0, x).forEach(...) 替换循环来修改局部变量并不能真正“使用流”,那么最好坚持使用 for 循环。

      【讨论】:

        猜你喜欢
        • 2011-12-08
        • 1970-01-01
        • 2023-04-01
        • 2013-12-15
        • 2013-11-21
        • 2011-04-12
        • 2016-05-25
        相关资源
        最近更新 更多