Java 8 Stream y operación en matrices

197

Acabo de descubrir las nuevas capacidades de transmisión de Java 8. Viniendo de Python, me preguntaba si ahora había una forma ordenada de hacer operaciones en matrices como sumar, multiplicando dos matrices en una forma "pitónica de una línea".

Gracias

BlackLabrador
fuente

Respuestas:

294

Se han agregado nuevos métodos java.util.Arrayspara convertir una matriz en una secuencia Java 8 que luego se puede usar para sumar, etc.

int sum =  Arrays.stream(myIntArray)
                 .sum();

Multiplicar dos matrices es un poco más difícil porque no puedo pensar en una forma de obtener el valor Y el índice al mismo tiempo que una operación Stream. Esto significa que probablemente tenga que transmitir sobre los índices de la matriz.

//in this example a[] and b[] are same length
int[] a = ...
int[] b = ...

int[] result = new int[a.length];

IntStream.range(0, a.length)
         .forEach(i -> result[i] = a[i] * b[i]);

EDITAR

El comentarista @Holger señala que puede usar el mapmétodo en lugar de hacerlo forEachasí:

int[] result = IntStream.range(0, a.length).map(i -> a[i] * b[i]).toArray();
dkatzel
fuente
13
int[] result=IntStream.range(0, a.length).map( i->a[i]* b[i]).toArray();
Holger
2
@ Holger sí, eso también funcionaría. Aunque probablemente quieras usar mapToIntpara evitar el boxeo.
dkatzel
Eso último equivale a una simulación de zip donde debe preasignar almacenamiento para el resultado. Me pregunto por qué no hay zip en la biblioteca Streams.
Reb.Cabin
De acuerdo con esta respuesta SO , un zip estaba en una versión beta anterior de Java 8 y luego se eliminó. Afortunadamente, el cartel tenía la fuente y está en la respuesta. He usado el código varias veces y parece funcionar muy bien.
sparc_spread
@dkatzel: dado que ya es un IntStream, "map" toma un IntUnaryOperator, por lo que no hay boxeo involucrado.
M. Justin
58

Puede convertir una matriz en una secuencia utilizando Arrays.stream():

int[] ns = new int[] {1,2,3,4,5};
Arrays.stream(ns);

Una vez que tenga su transmisión, puede usar cualquiera de los métodos descritos en la documentación , como sum()o lo que sea. Puede mapo le filtergusta en Python llamando a los métodos de transmisión relevantes con una función Lambda:

Arrays.stream(ns).map(n -> n * 2);
Arrays.stream(ns).filter(n -> n % 4 == 0);

Una vez que haya terminado de modificar su transmisión, llame toArray()para convertirla nuevamente en una matriz para usar en otro lugar:

int[] ns = new int[] {1,2,3,4,5};
int[] ms = Arrays.stream(ns).map(n -> n * 2).filter(n -> n % 4 == 0).toArray();
Ian Knight
fuente
9

Tenga cuidado si tiene que lidiar con grandes números.

int[] arr = new int[]{Integer.MIN_VALUE, Integer.MIN_VALUE};
long sum = Arrays.stream(arr).sum(); // Wrong: sum == 0

La suma anterior no es 2 * Integer.MIN_VALUE. Necesitas hacer esto en este caso.

long sum = Arrays.stream(arr).mapToLong(Long::valueOf).sum(); // Correct
Sanghyun Lee
fuente
3

Tenga en cuenta que Arrays.stream (arr) crea un LongStream (o IntStream, ...) en lugar de Stream, por lo que la función de mapa no puede utilizarse para modificar el tipo. Es por eso que se proporcionan las funciones .mapToLong, mapToObject, ...

Eche un vistazo a why-cant-i-map-integers-to-strings-when-streaming-from-an-array

Rafael
fuente