流迭代不使用最后一个值

Sni*_*192 2 java java-stream

简化示例

我有以下代码,它生成一系列的总和,即1, 1+2, 1+2+3, 1+2+3+4

public static void main(String[] args) {

    Stream<Integer> inputStream = Stream.of(1,2,3,4);
    Iterator<Integer> iterator = inputStream.iterator();
    
    Stream<Integer> outputStream = Stream.iterate(
            iterator.next(),
            i -> iterator.hasNext(),
            next -> {
                return iterator.next() + next;
            }
    );

    List<Integer> outputList = outputStream.collect(Collectors.toList());
    System.out.println(outputList);

}
Run Code Online (Sandbox Code Playgroud)

但这会打印:[1, 3, 6],缺少最后一个元素。

工作示例但需要原子变量

请注意,这似乎得到了我想要的正确检查,但是有更好的解决方案吗?看起来很糟糕:

public static void main(String[] args) {

    Stream<Integer> inputStream = Stream.of(1,2,3,4);
    Iterator<Integer> iterator = inputStream.iterator();

    AtomicBoolean check = new AtomicBoolean(true);

    Stream<Integer> outputStream = Stream.iterate(
        iterator.next(),
        i -> check.get(),
        next -> {
            check.set(iterator.hasNext());
            return iterator.hasNext() ? iterator.next() + next : next;
        }
    );

    List<Integer> outputList = outputStream.collect(Collectors.toList());
    System.out.println(outputList);

}
Run Code Online (Sandbox Code Playgroud)

一般问题描述

这是说明问题的通用代码。

public static <O, I> Stream<O> iterate(O seed, Stream<I> stream, BiFunction<I,O,O> function) {
    return iterate(seed, stream.iterator(), function);
}

public static <O, I> Stream<O> iterate(O seed, Iterator<I> iterator, BiFunction<I,O,O> function) {
    AtomicBoolean hasNext = new AtomicBoolean(true);
    return Stream.iterate(
        seed,
        i -> hasNext.get(),
        next -> {
            hasNext.set(iterator.hasNext());
            return iterator.hasNext() ? function.apply(iterator.next(), next) : next;
        }
    );
}

public static void main(String[] args) {
    
    Stream<Integer> inputStream = Stream.of(2,3,4);
    BiFunction<Integer, Integer, Integer> f = Integer::sum;
    Stream<Integer> outputStream = iterate(1, inputStream, f);
    
    List<Integer> outputList = outputStream.collect(Collectors.toList());
    System.out.println(outputList);
    
}
Run Code Online (Sandbox Code Playgroud)

问题背景

基本上,我想这样做是因为我正在创建一个函数来生成计息帐户余额的预测。

我希望能够获取一系列日期,然后生成一系列余额。这样您就不需要知道有多少元素,甚至不需要知道日期的分布,这使得它成为一种更灵活的方法。

另请注意, 的下一个元素Stream取决于前一个元素。这就是为什么我有一个seed代表第一个值(没有先前值)的原因,这将是期初余额。

Arv*_*ash 7

...但是有更好的解决方案吗?

是的,一个优雅的解决方案可以是使用Arrays#parallelPrefix.

public class Main {
    public static void main(String args[]) {
        int[] arr = { 1, 2, 3, 4 };
        Arrays.parallelPrefix(arr, Integer::sum);
        System.out.println(Arrays.toString(arr));
    }
}
Run Code Online (Sandbox Code Playgroud)

输出

[1, 3, 6, 10]
Run Code Online (Sandbox Code Playgroud)

您始终可以根据您的要求在Stream<Integer>和之间来回转换。int[]

public class Main {
    public static void main(String args[]) {
        int[] arr = Stream.of(1, 2, 3, 4).mapToInt(Integer::valueOf).toArray();
        Arrays.parallelPrefix(arr, Integer::sum);
        System.out.println(Arrays.toString(arr));

        // In case , you need a Stream<Integer> again
        Stream<Integer> resultStream = Arrays.stream(arr).boxed();

        // Or want the result as a List<Integer>
        List<Integer> resultList = resultStream.toList();
        System.out.println(resultList);
    }
}
Run Code Online (Sandbox Code Playgroud)