我有一个这样的数字列表:
[ 0, 1, 2, 3, 4, 5, 6, 7 ]
如何以优雅的方式总结每个N(让我们假设2)元素并将列表转换为:
[ 1, 5, 9, 13 ]
修改 我提出了以下解决方案:
List<Double> input = Arrays.asList(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0);
List<Double> output = new ArrayList<>();
int N = 2;
IntStream.range(0, (input.size() + N - 1) / N)
.mapToObj(i -> input.subList(i * N, Math.min(N * (i + 1), input.size())))
.mapToDouble(l -> l.stream().mapToDouble(Double::doubleValue).sum())
.forEach(output::add);
System.out.println(output);
它有效,但我仍然在寻找一种更易读,更简单的方法。
答案 0 :(得分:3)
这是另一种有效的方法,无论您的元素是否已排序。此外,它不会期望任何有关您的起始值的信息,并且会在更广泛的范围内给出正确的结果。即使list.size() % n == 0
条件不成立,此方法仍然有效。因此,从字面上看,它不需要任何先决条件即可获得所需的东西。
这种方法背后的直觉是您的索引是自然排序的,因此可以用来实现我们需要的内容。我们可以将元素归为一类,只要它们的当前索引i / n
产生相同的值即可。然后,使用下游收集器来计算属于同一组的元素之和。看起来就是这样。
Collection<Integer> sumsOfnElements = IntStream.range(0, numbers.size()).boxed()
.collect(Collectors.groupingBy(i -> i / n,
Collectors.summingInt(numbers::get))).values();
下面给出了遵循或多或少相同方法的等效迭代解。在性能严格的情况下,我会选择基于流的命令式解决方案。
假设:输入是一个整数数组,而不是一个列表。
final float inputLen = input.length;
final int resultLen = (int) Math.ceil(inputLen / n);
final int[] result = new int[resultLen];
for (int i = 0; i < inputLen; i++)
result[i / n] += input[i];
答案 1 :(得分:2)
假设:
List<Integer> numbers = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7);
int nth = 2;
怎么样:
IntStream.iterate(0, idx -> idx + nth)
.limit(numbers.size() / nth)
.map(idx -> IntStream.range(idx, idx + nth)
.reduce((sum, index) -> sum + numbers.get(index))
.orElse(0))
.forEach(System.out::println);
或者:
IntStream.range(0, numbers.size() / nth)
.map(idx -> IntStream.range(idx * nth, (idx + 1) * nth)
.map(index -> numbers.get(index))
.sum())
.forEach(System.out::println);
答案 2 :(得分:1)
这是使用Collectors.groupingBy()
的另一种方法:
List<Integer> numbers = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7);
int N = 2;
Collection<Integer> sums = numbers.stream()
.collect(Collectors.groupingBy(i-> i/N,
Collectors.summingInt(Integer::intValue)))
.values();
System.out.println (sums);
输出:
[1, 5, 9, 13]
答案 3 :(得分:0)
这个怎么样? (我已编辑过 int nTh = 2;
List<Integer> list = List.of(0, 1, 2, 3, 4, 5, 6, 7);
int[] result = IntStream.iterate(0, i -> i + nTh)
.limit(list.size() / nTh)
.map(x -> {
return IntStream.range(0, nTh).map(i -> list.get(i + x)).sum();
})
.toArray();
System.out.println(Arrays.toString(result));
)
ControlTemplate
答案 4 :(得分:0)
我认为最优雅的方法是使用flatMap,这样可以避免O(n²)的复杂性。 这是一个例子:
<!DOCTYPE html>
<html>
<body>
<p id="demo"></p>
<script>
var myObject, myArray;
function myFunction(func,val) {
var test = func.apply(test,val);
}
function myFunction2(val) {
alert(val)
}
myObject = myFunction(myFunction2, ['myArray called using apply ']); // Will return the value called from inside using `apply`
document.getElementById("demo").innerHTML = myObject;
</script>
</body>
</html>
这将输出:
public static class Helper {
private final int chunkSize;
private int index;
private int sum;
public Helper(int chunkSize) {
this.chunkSize = chunkSize;
}
public Stream<Integer> set(int v) {
index += 1;
sum += v;
ArrayList<Integer> ret = new ArrayList<>();
if (index == chunkSize) {
ret.add(sum);
sum = 0;
index = 0;
}
return ret.stream();
}
}
public static void main(String[] args) {
List<Integer> input = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7);
Helper helper = new Helper(2);
List<Integer> output = input.stream().flatMap(helper::set).collect(Collectors.toList());
System.out.println(input);
System.out.println(output);
}