Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 Lambda to convert Number[][] to double[][]

Number[][] intArray = new Integer[][]{ {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };
double[][] doubleArray = Arrays.stream(intArray)
                            .forEach(pArray -> Arrays.stream(pArray)
                                                .mapToDouble(d ->d.doubleValue())
                                                .toArray())
                            .toArray();

I want to convert a Number[][] to double[][]. The above lambda does not work, the outer toArray does not compile.

Arrays.stream(intArray) : Returns a stream of Integer[]
forEach : For every Integer[], creating a stream of Integers, converting each Integer into double and returning a double[].
The for each creates the double[] and I thought the outer toArray would return an array of this double[]
How can I get this to work?

like image 768
Nikhil Avatar asked Mar 20 '15 22:03

Nikhil


2 Answers

Here's how you could do it:

double[][] doubleArray = Arrays.stream(intArray)
                               .map(arr -> Stream.of(arr).mapToDouble(Number::doubleValue).toArray())
                               .toArray(double[][]::new);

This can be decomposed as follows:

First you use Arrays.stream to create a Stream<Number[]>. Then for each Number[], you create a Stream<Number>, and use mapToDouble to get DoubleStream and then toArray() to get the double[] array.

The final toArray call transforms this Stream<double[]> into a double[][] array.

like image 148
Alexis C. Avatar answered Sep 20 '22 14:09

Alexis C.


First of all forEach is terminal operator with return type of void so you can't use

stream().forEach(...).toArray();
//                   ^void returned here, and void doesn't have `toArray` method

You need to map your data into double[] rows, and then collect them into double[][], which brings us to your second problem since toArray() (from stream of objects) returns Object[] array which can't be stored in double[][] reference. You need to use

A[] toArray(IntFunction<A[]> generator)

which will return correct type of data, so you can use

toArray(size -> new double[size][])

or its shorter version

toArray(double[][]::new)

Here is how your code can look like:

double[][] doubleArray = Arrays.stream(intArray)
        .map(
                pArray -> Arrays
                .stream(pArray)
                .mapToDouble(d -> d.doubleValue())
                .toArray()
        ).toArray(double[][]::new);
        //which is equivalent of
//      ).toArray(size -> new double[size][]);

//---[Test]---
for (double[] row : doubleArray){
    System.out.println(Arrays.toString(row));
}

Output:

[1.0, 2.0, 3.0]
[4.0, 5.0, 6.0]
[7.0, 8.0, 9.0]
like image 37
Pshemo Avatar answered Sep 19 '22 14:09

Pshemo