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 (e.g. 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));
}