Filling a Multidimensional Array using a Stream Filling a Multidimensional Array using a Stream arrays arrays

Filling a Multidimensional Array using a Stream


Here you have a solution that produces the array instead of modifying a previously defined variable:

String[][] array =     IntStream.range(0, 3)             .mapToObj(x -> IntStream.range(0, 3)                                     .mapToObj(y -> String.format("%c%c", letter(x), letter(y)))                                     .toArray(String[]::new))             .toArray(String[][]::new);

If you want to use parallel streams then it's very important to avoid side effects like modifications of a variable (array or object). It might lead to race conditions or other concurrency issues. You can read more about that in java.util.stream package documentation - see Non-interference, Stateless behaviors and Side-effects sections.


The best way is a combination of the two approaches of Stuart Marks’ answer.

IntStream.range(0, array.length).forEach(x -> Arrays.setAll(    array[x], y -> String.format("%c%c", letter(x), letter(y))));

The reasoning leading to the solution is that “filling a multi-dimensional array” in Java means, “iterating over the outer array(s)” followed by “filling a one-dimensional array” as String[][] is just a an array of String[] elements in Java. In order to set their elements you have to iterate over all String[] elements and since you need the index to calculate the final value, you can’t use Arrays.stream(array).forEach(…). So for the outer array iterating over the indices is appropriate.

For the inner arrays the search is for the best solution for modifying an (one-dimensional) array. Here, Arrays.setAll(…,…) is appropriate.


There are a couple ways to do this.

One way is with a couple nested IntStreams over the row and column indexes:

String[][] testStream() {    String[][] array = new String[3][3];    IntStream.range(0, array.length).forEach(x ->         IntStream.range(0, array[x].length).forEach(y ->             array[x][y] = String.format("%c%c", letter(x), letter(y))));    return array;}

Another way which seems promising is to use Array.setAll instead of streams. This is great for generating values for a one-dimensional array: you provide a function that maps from the array index to the value you want assigned in the array. For example, you could do this:

String[] sa = new String[17];Arrays.setAll(sa, i -> letter(i));

Unfortunately it's less convenient for multidimensional arrays. The setAll method that takes a lambda that returns a value that's assigned to the array location at that index. If you've created a multidimensional array, the higher dimensions are already initialized with lower dimensional arrays. You don't want to assign to them, but you do want the implicit looping behavior of setAll.

With this in mind, you can use setAll to initialize the multidimensional array like this:

static String[][] testArraySetAll() {    String[][] array = new String[3][3];    Arrays.setAll(array, x -> {        Arrays.setAll(array[x], y -> String.format("%c%c", letter(x), letter(y)));        return array[x];    });    return array;}

The inner setAll is reasonably nice, but the outer one has to have a statement lambda that calls the inner setAll and then returns the current array. Not too pretty.

It's not clear to me that either of these approaches is any better than the typical nested for-loops.