Java-Streams - 以这样的方式转换数组,以便每个元素都依赖于前一个元素的值

问题描述 投票:0回答:6

假设我有一个像这样的累积数组

[0,1,3,6,10,15,21,28,36]

我想把它变成

[0,1,2,3,4,5,6,7,8]
,其中每个元素计算为:

value = [n] - [n-1]

有没有办法使用 Java 流 API 来实现此目的?

下面,您可以看到我的代码尝试。

尝试1:

confirmData = confirmedReader.readAll().stream()
    .map(cumulativeArr -> Arrays.stream(cumulativeArr).toArray(String[]::new))
    .toList();

尝试2:

confirmData = confirmedReader.readAll().stream().skip(1)
    .map(a -> {
        IntStream.range(0,a.length).forEach(x -> {
            a[x] = Integer.toString(Integer.parseInt(a[x]) - Integer.parseInt(a[x - 1]));
        });
    })
    .toList();
java arrays java-stream
6个回答
0
投票

使用IntStream能够达到给定的结果:

int[] arr = { 0, 1, 3, 6, 10, 15, 21, 28, 36 };
IntStream.range(0, arr.length - 1)
       .map(i -> arr[i + 1] - arr[i])
       .forEach(System.out::println);

输出:

1
2
3
4
5
6
7
8

0
投票

不确定你从哪里获取数据,但假设你能够将其转换为 int 数组,你可以使用

Arrays.setAll
方法:

int[] original = {0,1,3,6,10,15,21,28,36};
int[] result   = new int[original.length];

Arrays.setAll(result, i -> i > 0 ? original[i] - original[i-1] : original[i] );

System.out.println(Arrays.toString(result));

0
投票

“naive”方法将使用 Stream.range()

Stream.iterate()
来模仿传统的基于索引的
for
循环。
但请注意,

Stream

本质上是一个内部迭代器,这意味着Streams背后的核心思想是你不控制国际化过程,你不通过它的索引检索下一个元素,而不是检查是否存在。使用流,你需要考虑转换和累加逻辑,但需要考虑迭代的过程。 如果您选择

使用索引拨号

,那么@Eritrean介绍的利用Arrays.setAll()的解决方案是最干净的。

但是如果你真的想应用 Streams 来解决这个问题而不是操纵索引,那么任务就会变得有点棘手。

我提出了以下解决方案,该解决方案利用通过

Collector.of() 创建的 自定义收集器

Deque

用作收集器的

可变容器
的类型(List也很好,选择
Deque
是因为它有助于方便地访问最后一个元素)。在减少的每一步中,
accumulator
函数都会轮询最后一个元素(如果存在)并将轮询元素与流中的下一个元素之间的差异添加到deque中,然后它还存储下一个元素本身(请遵循代码中的注释以更好地理解它)。 int[] source = {0, 1, 3, 6, 10, 15, 21, 28, 36}; List<Integer> result = Arrays.stream(source).boxed() .collect(Collector.of( // Creating a custom Collector ArrayDeque::new, // Mutable Container of the Collector (Deque<Integer> deque, Integer next) -> { // Accumulator - adding stream element into the Container if (deque.isEmpty()) deque.addLast(next); else deque.addLast(next - deque.pollLast()); deque.addLast(next); // supplementary element which would be used in the else clause of the Accumulator as well as in the Combiner while running parallel and skipped by the Finisher in sequential }, (left, right) -> { // Combiner - merging Container containing intermediate results while executing in parallel (each thread would be given it's own chunk of data and would create its own Deque which will be populated according to the logic represented in the Accumulator) left.addLast(right.pollFirst() - left.pollLast()); // supplementary element is being polled from the Left Deque here left.addAll(right); return left; }, deque -> deque.stream().limit(source.length).toList() // Finisher - transforming Deque into a List )); System.out.println(result);

输出:

[0, 1, 2, 3, 4, 5, 6, 7, 8]



0
投票

int[] original = { 0, 1, 3, 6, 10, 15, 21, 28, 36 }; List<Integer> ls = IntStream.range(0, original.length).collect(ArrayList<Integer>::new, (x, y) -> { if (y == 0) x.add(original[y]); else x.add(original[y] - original[y - 1]); }, List::addAll); System.out.println(ls);

输出:

[0,1,2,3,4,5,6,7,8]

请注意,这会返回列表输出,正如我根据您的问题所看到的那样,您正在寻找列表输出。


0
投票
guava

包通过 Ints.indexOf(array , target) : 来精细索引元素

算法:值 = n - (n-1)

如果 0 继续,否则 1 = 1 - 0 , 2 = 3 - 1 , 3 = 6 - 3 ... 等等

int[] source = {0, 1, 3, 6, 10, 15, 21, 28, 36}; List<Integer> list = Arrays.stream(source). map(s-> s = s != 0 ? s - source[Ints.indexOf(source, s) - 1] : s). boxed().collect(Collectors.toList()); System.out.println(list);
打印:

[0, 1, 2, 3, 4, 5, 6, 7, 8]



0
投票
JEP 461:Stream Gatherers

Java 22 预览语言功能添加了对滑动窗口流式传输的内置支持,这非常适合: list.stream() .gather(Gatherers.windowSliding(2)) .map(w -> w.getLast() - w.getFirst()) .toList();

这使用新的 

Stream.gather

 方法和新的内置 
Gatherers.windowSliding
 收集器将初始 
Stream<Integer>
转换为成对
Stream<List<Integer>>
。然后使用现有的
Stream.map
 方法将这些成对列表映射到元素之间的差异。
Java文档

Gatherer

将输入元素流转换为输出元素流的中间操作,可以选择在到达上游末尾时应用最终操作。 […]

[…]

聚集操作的例子有很多,包括但不限于:将元素分组(窗口函数);对连续相似的元素进行去重;增量累加功能(前缀扫描);增量重新排序功能等。类

Gatherers

提供了常见收集操作的实现。

Stream.gather

返回一个流,其中包含将给定收集器应用于该流的元素的结果。

Gatherers.windowSliding



返回一个 Gatherer,它将元素收集到给定大小的窗口(遇到有序的元素组)中,其中每个后续窗口都包含前一个窗口的所有元素(除了最近的元素之外),并在流中添加下一个元素。 […]

示例:

// will contain: [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8]] List<List<Integer>> windows2 = Stream.of(1,2,3,4,5,6,7,8).gather(Gatherers.windowSliding(2)).toList(); // will contain: [[1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7], [3, 4, 5, 6, 7, 8]] List<List<Integer>> windows6 = Stream.of(1,2,3,4,5,6,7,8).gather(Gatherers.windowSliding(6)).toList();

    
© www.soinside.com 2019 - 2024. All rights reserved.