数组元素的总和

时间:2022-06-28 21:23:35

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.

我在ArrayList中有n个数组。数组的数量不是预先确定的,而数组的大小是固定的,但它可以包含空元素,空值被认为是零。我需要将每个单元格的总和放入新数组中的相应索引中,其大小在逻辑上与其他数组相同。

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)

我有一个经典的迭代方法的解决方案,但我最终得到一个非常脏的实现。我很乐意看到您解决此问题的方法(最好使用Stream api)

3 个解决方案

#1


14  

Here's a way to do it, inspired by shmosel's answer:

这是一种方法,灵感来自shmosel的答案:

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

#2


28  

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];
  }
}

#3


13  

Here's a solution using streams:

这是使用流的解决方案:

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

#1


14  

Here's a way to do it, inspired by shmosel's answer:

这是一种方法,灵感来自shmosel的答案:

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

#2


28  

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];
  }
}

#3


13  

Here's a solution using streams:

这是使用流的解决方案:

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