简体   繁体   中英

How to map n-Dimensional Array to another type using Java-8 Streams?

I have a double[][] and I would like to convert it to BigDecimal[][] . I could perform the following:

public static BigDecimal[][] convert(double[][] arr1){
    BigDecimal[][] arr2 = new BigDecimal[arr1.length][arr1[0].length];
    for(int i = 0; i < arr1.length; i++){
        for(int j = 0; j < arr1[0].length; j++){
            arr2[i][j] = new BigDecimal(arr1[i][j]);
        }
    }
    return arr2;
}

How can I perform this operation using streams in Java-8?

In general, given an object of type Foo with a constructor that takes a single object of type Bar , what is the best way to convert a Bar[][] to a Foo[][] using a stream? How about a Bar[][][] to a Foo[][][] ?

Conversion in a single dimension is straight-forward. The code I'm using for a 1D-arrays is:

pubilc static Foo[] convert(Bar[] bars){
    return Arrays.stream(bars).mapToObj(Foo::new).toArray(Foo[]::new); 
}

How can this be accomplished in 2-dimensions? What about 3- or 4- dimensions? Is it possible to write a recursive method that converts an n -dimensional array of one type to an n -dimensional array of another type?

The straight-forward way:

public static BigDecimal[][] convert(double[][] arr1){
    return Arrays.stream(arr1).map(
        r -> Arrays.stream(r).mapToObj(BigDecimal::new).toArray(BigDecimal[]::new)
    ).toArray(BigDecimal[][]::new);
}

This creates a Stream<double[]> from the input array, maps each double[] to a BigDecimal[] (by creating a DoubleStream and mapping each double to a new BigDecimal ) and finally makes an BigDecimal[][] array of that Stream.


Extending this to a 3D array is the same logic: we make a Stream<double[][]> of the input array, convert each double[][] to a BigDecimal[][] by the preceding code and convert that back into an array.

public static BigDecimal[][][] convert(double[][][] arr1){
    return Arrays.stream(arr1).map(r -> convert(r)).toArray(BigDecimal[][][]::new);
}

Thanks to Holger , that corrected my initial approach, this can be extended to a n dimensional array with the following. The restriction is you need special care for primitive arrays.

public static <T> T[] convert(
    Object[] array, Function<Object, Object> mapper, Class<T[]> returnClass) {

    Class componentType = returnClass.getComponentType();
    return Arrays.stream(array)
                 .map(array instanceof Object[][]?
                      r -> convert((Object[])r, mapper, componentType): mapper::apply)
                 .toArray(i -> returnClass.cast(Array.newInstance(componentType, i)));
}

(Note, you might need to import java.lang.reflect.Array explicitely). Tested with

public static void main(String[] args) {
    Double[][] d = { { 0.1 }, { }, { 0.2, 0.3 } };
    BigDecimal[][] bd=convert(d, v -> new BigDecimal((Double) v), BigDecimal[][].class);
    System.out.println(Arrays.deepToString(bd));
}

When using it with primitive arrays, you have to handle the last dimension (eg double[] ) with the mapper function, as one-dimensional primitive arrays are not instances of Object[] and can't be processed with the generic code. One example usage is

public static void main(String[] args) {
    double[][][] da= { {{ 0.1 }, { }}, {{ 0.2, 0.3 }, { 0.4 }} };
    BigDecimal[][][] bd=convert(da,
      v -> Arrays.stream((double[])v).mapToObj(BigDecimal::new).toArray(BigDecimal[]::new),
      BigDecimal[][][].class);
    System.out.println(Arrays.deepToString(bd));
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM