如何使用 lambda 表达式计算整数列表中的差异

How to calculate differences in a list of integers using lambda expressions

假设我有以下数组:{1,2,3,4,6,7,8} 放在 Stream<Integer> s = Stream.of(1,2,3,4,6,7,8);

如何在 Java 中使用 lambda 表达式和 Stream 函数来计算每个元素与下一个元素(在本例中为 {1,1,1,2,1,1})之间的差异? 这并不是真正的 reduce 操作,因为 reduce 将整个列表转换为 1 个元素;它也不是映射操作,因为它需要两个元素来计算差异,而不仅仅是一个。

您可以遍历索引而不是元素,例如

int s[] = {1, 2, 3, 4, 6, 7, 8};
IntStream differences = 
    IntStream.range(0, s.length - 1)
        .map(i -> s[i + 1] - s[i]);

另一个答案似乎已经被接受,但我有一个想法,所以我 post 无论如何。您可以制作一个 Collector 将其直接收集到另一个 Stream<Integer>.

那么你可以这样写:

s.collect(intDifferences()).forEach(d -> System.out.print(d + ","));

这是我写的一个实现:

public static Collector<Integer, List<Integer>, Stream<Integer>> intDifferences() {

    return new Collector<Integer, List<Integer>, Stream<Integer>>() {

        @Override
        public BiConsumer<List<Integer>, Integer> accumulator() {
            return List::add;
        }

        @Override
        public Set<Collector.Characteristics> characteristics() {
            return EnumSet.noneOf(Collector.Characteristics.class);
        }

        @Override
        public BinaryOperator<List<Integer>> combiner() {
            return (left, right) -> {
                left.addAll(right);
                return left;
            };
        }

        @Override
        public Function<List<Integer>, Stream<Integer>> finisher() {
            return list -> {
                List<Integer> differences = new ArrayList<>();
                for (int i = 1; i < list.size(); i++) {
                    differences.add(list.get(i) - list.get(i - 1));
                }
                return differences.stream();
            };
        }

        @Override
        public Supplier<List<Integer>> supplier() {
            return ArrayList::new;
        }
    };
}

如果您允许映射函数有副作用,则可以使用 map(),即您可以在流中存储对前一个对象的引用:

Stream.of(1, 2, 3, 4, 6, 7, 8)
    .map(new Function<Integer, Optional<Integer>>() {
        Optional<Integer> previousValue = Optional.empty();
        @Override
        public Optional<Integer> apply(Integer current) {
            Optional<Integer> value = previousValue.map(previous -> current - previous);
            previousValue = Optional.of(current);
            return value;
        }
    })
    .filter(Optional::isPresent)
    .map(Optional::get)
    .forEach(System.out::println);

请注意,此实现不是 pure function,因此您必须注意它的使用方式。上面的示例有效,因为该函数每次都被实例化(特别是 previousValue 将在每次使用时重置)。但是,如果重构代码,将函数存储在局部变量中,它将起作用,因为第二次使用该函数时,previousValue将不会空的。因此,通常不鼓励这种实施方式。

这种情况你可以使用我的StreamEx library which has a pairMap方法:

StreamEx<Integer> s = StreamEx.of(1,2,3,4,6,7,8);
s = s.pairMap((a, b) -> b-a);
s.forEach(System.out::println);

StreamEx class 实现了 Stream 并与其完全兼容。同样的事情也适用于原始流:

IntStreamEx s = IntStreamEx.of(1,2,3,4,6,7,8);
s = s.pairMap((a, b) -> b-a);
s.forEach(System.out::println);
public int[] diff(int... input) {
    AtomicInteger aInt = new AtomicInteger();
    return IntStream.of(input).map(v -> v - aInt.getAndSet(v)).skip(1).toArray();
}

不是纯函数,因为它改变了 AtomicInteger 的状态