Как инициализировать двумерный массив в Java 8 - PullRequest
0 голосов
/ 28 августа 2018

Перед версиями Java 8 мы можем инициализировать двумерный массив, используя цикл for, как показано ниже. Как я могу сделать ниже в 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]]

Ответы [ 4 ]

0 голосов
/ 28 августа 2018

Вот потоковое решение, которое «вложено в циклы» выглядит следующим образом.

  1. Получить последовательность чисел от 0 до N (исключая верхний предел -> N = board.length;
  2. Получить последовательность чисел от 0 до M (исключая верхний предел -> M = board [i] .length;
  3. Для каждой пары (i, j) установите значение платы [i] [j], используя func (i + j * step + 1), где step определяется как 5.

Выход для int [] [] board = new int [4] [2];

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

Выход для int [] [] board = 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
    )
);
0 голосов
/ 28 августа 2018

Я настоятельно рекомендую вам использовать 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[] больше не является примитивным значением, а сам массив. Необходимо использовать метод IntStream::mapToObj, который отображает int на объект - тогда возвращается Stream<int[]> и метод Stream::toArray(IntFunction<A[]> generator) необходимо использовать преобразование в массив с параметром, поскольку вы не можете преобразовать Object[] в int[][].

Переданный параметр прост. int[][]::new ничем не отличается от i -> new int[a][b].

0 голосов
/ 28 августа 2018

Вы можете использовать комбинацию методов IntStream range и iterate:

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(...) для изменения локальной переменной на самом деле не "использует потоки", и тогда лучше придерживаться циклов.

0 голосов
/ 28 августа 2018

Используйте IntStream. Это создаст непрерывный поток целых чисел от 0 включительно до n эксклюзивно. Таким образом, для матрицы 3 x 3 IntStream равно 0, 1, 2. сделать еще одно IntStream для каждого целого числа во внешнем потоке от 0 до количества столбцов - также 3.

Вы не можете увеличить v в потоке, потому что он должен быть "эффективно финальным". Вместо этого мы используем уравнение board[j][i] = 1 + (j + m * i), которое фактически аналогично вычислению индекса значения, если вы собираете плату в один массив (1D матрица).

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 (особенно при работе с массивами).

Помните, простота - это ключ.

...