如何在Java 8中初始化二维数组

时间:2018-08-27 23:55:04

标签: java arrays java-8 java-stream

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

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]]

4 个答案:

答案 0 :(得分:1)

使用IntStream。这将创建一个连续的整数流,从0n不包括整数。因此,对于3 x 3矩阵,IntStream0, 1, 2。 为外部流中从IntStream到列数(也为3)的每个整数再创建一个0

您不能在流中递增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 :(得分:0)

我强烈建议您坚持使用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可以创建一个基本数组,因为它是一个基本整数值元素的序列。其方法IntStream::toArray要求int[]

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

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

答案 2 :(得分:0)

您可以结合使用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循环。

答案 3 :(得分:0)

这里是“嵌套循环”的流解决方案。

  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
    )
);