如何使用 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 的状态
假设我有以下数组:{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 的状态