2016-02-03 1 views
1

У меня есть double[][], и я хотел был бы преобразовать его в BigDecimal[][]. Я мог выполнить следующие действия:Как сопоставить n-мерный массив с другим типом с использованием потоков Java-8?

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; 
} 

Как я могу выполнить эту операцию с помощью потоков в Java-8?

В общем, данный объект типа Foo с конструктором, который принимает один объект типа Bar, что это лучший способ, чтобы преобразовать Bar[][] к Foo[][] с использованием потока? Как насчет Bar[][][] до Foo[][][]?

Конверсия в одном измерении прямолинейна. Код, я использую в течение 1D-массивов:

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

Как это может быть достигнуто в 2-х измерениях? Что относительно 3- или 4-мерных размеров? Можно ли написать рекурсивный метод, который преобразует массив n одного типа в массив n другого типа?

ответ

3

Прямой вперед путь:

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

Это создает Stream<double[]> из входного массива, отображает каждый double[] к BigDecimal[] (путем создания DoubleStream и отображения каждого double к новому BigDecimal) и, наконец, делает BigDecimal[][] массив этого потока.


Расширения этого 3D-массив является той же логикой: мы делаем Stream<double[][]> из входного массива, преобразовать каждый double[][] к BigDecimal[][] в предыдущем коде и преобразовать его обратно в массив.

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

Благодаря Holger, что исправленному моему первоначальному подход, это может быть расширено до n одномерного массива со следующим. Ограничение - вам нужна особая забота о примитивных массивах.

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))); 
} 

(Обратите внимание, что вам может понадобиться импортировать java.lang.reflect.Array явно). Испытано с

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)); 
} 

При его использовании с примитивными массивами, вы должны обрабатывать последнее измерение (например, double[]) с функцией картографа, так как одномерные примитивные массивы не являются экземплярами Object[] и не могут быть обработаны общий код. Одним из примеров является

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)); 
}