2

Before Java 8 versions, we can initialize a two-dimensional array using for loop like below. How can I do the below in JDK 1.8 using lambda expressions?

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

Basically, I am looking for an array like below

[[1,6],[2,7],[3,8],[4,9]]
5
  • int[][] board = IntStream.range(0, 3).mapToObj(i -> IntStream.range(0, 3).map(j -> i * 3 + j + 1).toArray()).toArray(int[][]::new); Commented Aug 27, 2018 at 23:58
  • Thanks @shmosel, I would like to have an array like below [[1,6],[2,7],[3,8],[4,9]] Commented Aug 28, 2018 at 0:16
  • 4
    Traditional for loop has better readability and better efficiency especially when handling primitive types. I would recommend using traditional for loop unless you are required otherwise. Commented Aug 28, 2018 at 0:50
  • 2
    is 5 intentionally missing or just forgotten? Commented Aug 28, 2018 at 1:49
  • Your loop doesn't produce that. Commented Aug 28, 2018 at 6:33

4 Answers 4

5

I highly recommend you stick with using the for-loop for initialization of arrays with primitive values. My recommendation is stronger in the case of a multidimensional array.

However, here is the way:

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

Note that the IntStream is able to create an array of primitives since it is a sequence of primitive int-valued elements. its method IntStream::toArray reutrns int[].

The composition of the outer array is a bit tricky since int[] is no longer a primitive value but an array itself. There is needed to use a method IntStream::mapToObj which maps int to an object - then the Stream<int[]> is returned and the method Stream::toArray(IntFunction<A[]> generator) converting to array with parameter has to be used since you cannot convert Object[] to int[][].

The parameter passed is simple. int[][]::new is nothing different than i -> new int[a][b].

Sign up to request clarification or add additional context in comments.

Comments

4

Use IntStream. This will create a continuous stream of integers from 0 inclusive to n exclusive. So for a 3 x 3 matrix, the IntStream is 0, 1, 2. make another IntStream for each integer in the outer stream from 0 to number of columns - also 3.

You cannot increment v in a stream because it must be "effectively final". Instead we use the equation board[j][i] = 1 + (j + m * i) which is effectively the similar to computing the index of the value if you were to flatten board into a single array (1D matrix).

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

  }

}

Output:

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

Note: Just because streams allow you to write a neater, functional programming-like syntax, there is often times an associated performance toll. It stresses the idea, "why fix what's not broken?". For a 3 x 3 board, you probably won't see a difference. But, if your board were a lot larger, it probably won't prove itself to be worth it, considering all the objects created and extra space used behind the scene. Sometimes a simple for-loop (especially when working with arrays) is better.

Remember, simplicity is key.

3 Comments

Thanks. I want like [[1,6],[2,7],[3,8],[4,9]]
@sc1234 What about 5? You skipped 5 in your sequence. You need to make the matrix 4 x 2 (4 rows each of which with 2 columns) You specified the board to be 3 x 3. Meaning you have 3 rows, 3 columns. Your expected output is not consistent with the input you supplied us to work with.
@sc1234 Edits made
0

Here is a stream solution that is "nested for cycles" look a like.

  1. Get the sequence of the numbers from 0 to N(Upper limit exclusive -> N = board.length;
  2. Get the sequence of the numbers from 0 to M(Upper limit exclusive -> M = board[i].length;
  3. For each of the couples (i, j) set the value of board[i][j] using the func (i + j * step + 1) where step is defined as 5.

Output for int[][] board = new int[4][2];

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

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

Comments

0

You can use a combination of the IntStream methods range and iterate:

int width = 4, height = 2;

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

By using iterate for the inner loop and rangeClosed(1, width) instead of range(0, width) we can simplify the calcuation a bit. Using toArray removes the need to create and modify the array yourself and would enable parallel processing.

It is important to actually use streams properly to make them more than just weird looking for loops. Merely replacing your loop by a range(0, x).forEach(...) to modify a local variable does not really "use streams", and it is better to stick to for loops then.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.