How to initialize two dimensional array in java 8
How to initialize two dimensional array in java 8
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]]
int board = IntStream.range(0, 3).mapToObj(i -> IntStream.range(0, 3).map(j -> i * 3 + j + 1).toArray()).toArray(int::new);
Thanks @shmosel, I would like to have an array like below [[1,6],[2,7],[3,8],[4,9]]
– sc1234
Aug 28 at 0:16
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.– KaiserKatze
Aug 28 at 0:50
for
for
is
5 intentionally missing or just forgotten?– Carlos Heuberger
Aug 28 at 1:49
5
Your loop doesn't produce that.
– shmosel
Aug 28 at 6:33
4 Answers
4
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.
for-loop
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.
IntStream
IntStream::toArray
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.
int
IntStream::mapToObj
int
Stream<int>
Stream::toArray(IntFunction<A> generator)
Object
int
The parameter passed is simple. int::new is nothing different than i -> new int[a][b].
int::new
i -> new int[a][b]
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.
IntStream
0
n
IntStream
0, 1, 2
IntStream
0
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).
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));
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.
Thanks. I want like [[1,6],[2,7],[3,8],[4,9]]
– sc1234
Aug 28 at 1:14
@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.– Jabari Dash
Aug 28 at 1:24
4 x 2
3 x 3
@sc1234 Edits made
– Jabari Dash
Aug 28 at 1:31
Here is a stream solution that is "nested for cycles" look a like.
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
)
);
You can use a combination of the IntStream methods range and iterate:
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);
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.
iterate
rangeClosed(1, width)
range(0, width)
toArray
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.
range(0, x).forEach(...)
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
int board = IntStream.range(0, 3).mapToObj(i -> IntStream.range(0, 3).map(j -> i * 3 + j + 1).toArray()).toArray(int::new);– shmosel
Aug 27 at 23:58