I have a question for the following scenario;
I have n-number
arrays in an ArrayList
. The number of arrays is not predetermined, while the size of the array is fixed but it can contain null elements in it and the null values are considered as zero. I need to get the sum of each cell into the corresponding index in the new array, whose size is logically same as other arrays.
I tried to depict the scenario as follows;
I have a solution with classical way of iteration but I end up with a very dirty implementation. I would be happy to see your solution for this problem (preferably with Stream api
)
A non-streams solution (because I don't think that an as-easily-understandable solution would be possible in streams):
int[] result = new int[n]; // n is the length of each array.
for (Integer[] array : arrays) {
for (int i = 0; i < n; ++i) {
// Increment the i-th element of the result by the i-th element of array.
// Use 0 in place of null.
result[i] += array[i] != null ? array[i].intValue() : 0;
// or (suggested by shmosel)
// if (array[i] != null) result[i] += array[i];
}
}
Here's a way to do it, inspired by shmosel's answer:
Integer[] result = new Integer[FIXED_SIZE];
Arrays.setAll(result, i -> list.stream().mapToInt(a -> a[i] == null ? 0 : a[i]).sum());
Another way would be with a custom collector:
static <T> Collector<T[], ?, T[]> reducingByColumn(
T identity,
BinaryOperator<T> operator,
IntFunction<T[]> factory) {
return Collector.of(
HashMap<Integer, T>::new,
(map, a) -> IntStream.range(0, a.length)
.forEach(i -> map.merge(i, a[i] == null ? identity : a[i], operator)),
(m1, m2) -> {
m2.forEach((k, v) -> m1.merge(k, v, operator));
return m1;
},
map -> map.values().toArray(factory.apply(map.size())));
}
This collector uses a map to accumulate intermediate results.
You could use it as follows:
Integer[] result = list.stream()
.collect(reducingByColumn(0, Integer::sum, Integer[]::new));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With