Java 8 Stream и работа с массивами

197

Я только что открыл новые возможности потока Java 8. Исходя из Python, мне было интересно, есть ли теперь удобный способ выполнять операции над массивами, такие как суммирование, умножение двух массивов "питонным" способом?

Спасибо

BlackLabrador
источник

Ответы:

294

Для java.util.Arraysпреобразования массива в поток Java 8 добавлены новые методы, которые затем можно использовать для суммирования и т. Д.

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

Умножение двух массивов немного сложнее, потому что я не могу придумать способ получить значение И индекс одновременно с операцией Stream. Это означает, что вам, вероятно, придется перемещаться по индексам массива.

//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]);

РЕДАКТИРОВАТЬ

Комментатор @Holger указывает, что вы можете использовать mapметод вместо forEachэтого:

int[] result = IntStream.range(0, a.length).map(i -> a[i] * b[i]).toArray();
dkatzel
источник
13
int[] result=IntStream.range(0, a.length).map( i->a[i]* b[i]).toArray();
Хольгер
2
@ Хольгер, да, это тоже сработает. Хотя вы, вероятно, хотите использовать, mapToIntчтобы избежать бокса.
dkatzel
Последнее означает симуляцию zip, где вы должны предварительно выделить память для результата. Интересно, почему в библиотеке Streams нет zip?
Реб. Кабин
Согласно этому SO-ответу , zip был в более ранней бета-версии Java 8, а затем был снят. К счастью, у автора был источник, и он есть в ответе. Я использовал код несколько раз, и он, кажется, работает очень хорошо.
sparc_spread
@dkatzel - Поскольку это уже IntStream, для «карты» требуется IntUnaryOperator, поэтому в этом нет никакого участия в боксе.
М. Джастин
58

Вы можете превратить массив в поток, используя Arrays.stream():

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

После того, как вы получили свой поток, вы можете использовать любой из методов, описанных в документации , например, sum()или как угодно. Вы можете mapили filterкак в Python, вызывая соответствующие методы потока с помощью функции Lambda:

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

Как только вы закончите модифицировать ваш поток, вы вызываете, toArray()чтобы преобразовать его обратно в массив для использования в другом месте:

int[] ns = new int[] {1,2,3,4,5};
int[] ms = Arrays.stream(ns).map(n -> n * 2).filter(n -> n % 4 == 0).toArray();
Ян Найт
источник
9

Будьте осторожны, если вам приходится иметь дело с большими числами.

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

Сумма выше не является 2 * Integer.MIN_VALUE. Вы должны сделать это в этом случае.

long sum = Arrays.stream(arr).mapToLong(Long::valueOf).sum(); // Correct
Санхьюн Ли
источник