我对以下情况有疑问;
我在n-number
中有ArrayList
个数组。数组的数量不是预先确定的,而数组的大小是固定的,但它可以包含空元素,空值被认为是零。我需要将每个单元格的总和放入新数组中的相应索引中,其大小在逻辑上与其他数组相同。
我试图将场景描述如下;
我有一个经典的迭代方法的解决方案,但我最终得到了一个非常脏的实现。我很乐意看到您解决此问题的方法(最好使用Stream api
)
答案 0 :(得分:28)
非流解决方案(因为我不认为在流中可以使用易于理解的解决方案):
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];
}
}
答案 1 :(得分:14)
这是一种方法,灵感来自shmosel's answer:
Integer[] result = new Integer[FIXED_SIZE];
Arrays.setAll(result, i -> list.stream().mapToInt(a -> a[i] == null ? 0 : a[i]).sum());
另一种方法是使用自定义收集器:
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())));
}
此收集器使用地图累积中间结果。
您可以按如下方式使用它:
Integer[] result = list.stream()
.collect(reducingByColumn(0, Integer::sum, Integer[]::new));
答案 2 :(得分:13)
以下是使用流的解决方案:
final int SIZE = ...
List<Integer[]> arrays = ...
Integer[] result = IntStream.range(0, SIZE)
.map(i -> arrays.stream()
.map(arr -> arr[i])
.filter(Objects::nonNull)
.mapToInt(Integer::intValue)
.sum())
.boxed()
.toArray(Integer[]::new);