Java 8 Stream e operação em matrizes

197

Acabei de descobrir os novos recursos de fluxo do Java 8. Vindo de Python, eu queria saber se havia agora uma maneira elegante de fazer operações em matrizes como soma, multiplicando duas matrizes de uma maneira "uma linha pitônica"?

obrigado

BlackLabrador
fonte

Respostas:

294

Foram adicionados novos métodos java.util.Arrayspara converter uma matriz em um fluxo Java 8 que pode ser usado para somar, etc.

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

Multiplicar duas matrizes é um pouco mais difícil, porque não consigo pensar em uma maneira de obter o valor E o índice ao mesmo tempo que uma operação de Stream. Isso significa que você provavelmente precisará transmitir sobre os índices da 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

O Commenter @Holger indica que você pode usar o mapmétodo em vez de forEach:

int[] result = IntStream.range(0, a.length).map(i -> a[i] * b[i]).toArray();
dkatzel
fonte
13
int[] result=IntStream.range(0, a.length).map( i->a[i]* b[i]).toArray();
Holger
2
@ Holger sim, isso também funcionaria. Embora você provavelmente queira usar mapToIntpara evitar o boxe.
dkatzel
Essa última equivale a uma simulação de zip, na qual você deve pré-alocar o armazenamento para o resultado. Gostaria de saber por que não há zip na biblioteca do Streams?
Reb.Cabin
De acordo com essa resposta do SO , um zip estava em uma versão beta anterior do Java 8 e depois retirado. Felizmente, o pôster tinha a fonte e está na resposta. Eu usei o código várias vezes e parece funcionar muito bem.
Sparc_spread
@dkatzel - Como já é um IntStream, "map" usa um IntUnaryOperator, portanto não há boxe envolvido.
237 Justin
58

Você pode transformar uma matriz em um fluxo usando Arrays.stream():

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

Depois de obter seu fluxo, você pode usar qualquer um dos métodos descritos na documentação , como sum()ou o que quer. Você pode gostar mapou filtergostar do Python chamando os métodos de fluxo relevantes com uma função Lambda:

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

Depois de modificar o seu fluxo, chame-o toArray()para convertê-lo novamente em uma matriz para usar em outro 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
fonte
9

Tenha cuidado se você tiver que lidar com grandes números.

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

A soma acima não é 2 * Integer.MIN_VALUE. Você precisa fazer isso neste caso.

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