This question already has answers here:
Collect successive pairs from a stream
(20个答案)
4年前关闭。
在掌握Java 8流的过程中,以下练习使我停了下来。
给定
我想到了使用Collectors.collectAndThen将其传递到良好的旧列表或数组,然后循环构建字符串列表,如下所示:
但是它不使用流的力量。我感到Venkat Subramaniam说:“之后我想洗个澡”。
我想知道如何应用功能技术,以便在编码后跳过淋浴!
另外,我想避免使用StreamEx或JavaRx之类的库,而是要坚持使用普通的Java 8 API。
编辑:
@Tunaki,感谢您指出我的问题中措辞不清楚。它是由Stream的两个连续元素组成的一对。更具体地说,像
编辑2
向所有答案致敬后,尽管我的问题与Tunaki指出的另一个问题重复。我想在社区中讨论波希米亚的答案。尽管他的回答被某些人不满意,但它提出了一个严重的问题,即减少副作用的操作。我对社区的要求是针对此问题提供合理的反有效技术。因此,我想按以下方式重用波希米亚答案:
给定输入:nums = new int [] {1,3,5,7,9}
请考虑以下代码段:
此处
用法示例:
输出:
(20个答案)
4年前关闭。
在掌握Java 8流的过程中,以下练习使我停了下来。
给定
IntStream.range(0, 6)
。在下面产生字符串流:"0, 1"
"1, 2"
"2, 3"
"3, 4"
"4, 5"
我想到了使用Collectors.collectAndThen将其传递到良好的旧列表或数组,然后循环构建字符串列表,如下所示:
List<String> strgs = new ArrayList<>();
String prev = String.valueOf(nums[0]);
for (int i = 1; i < nums.length; i++) {
strgs.add(prev+", "+String.valueOf(nums[i]));
prev = String.valueOf(nums[i]);
}
但是它不使用流的力量。我感到Venkat Subramaniam说:“之后我想洗个澡”。
我想知道如何应用功能技术,以便在编码后跳过淋浴!
另外,我想避免使用StreamEx或JavaRx之类的库,而是要坚持使用普通的Java 8 API。
编辑:
@Tunaki,感谢您指出我的问题中措辞不清楚。它是由Stream的两个连续元素组成的一对。更具体地说,像
[1, 3, 5, 7, 9, ...]
这样的Stream将是"1, 3"
"3, 5"
"5, 7"
...
编辑2
向所有答案致敬后,尽管我的问题与Tunaki指出的另一个问题重复。我想在社区中讨论波希米亚的答案。尽管他的回答被某些人不满意,但它提出了一个严重的问题,即减少副作用的操作。我对社区的要求是针对此问题提供合理的反有效技术。因此,我想按以下方式重用波希米亚答案:
给定输入:nums = new int [] {1,3,5,7,9}
请考虑以下代码段:
List<CharSequence> stringList = new ArrayList<>();
IntBinaryOperator reductionWithSideEffect = (int left, int right) -> {
stringList.add(new StringBuilder().append(left).append(", ").append(right));
return right;
};
Arrays.stream(nums)
.reduce(reductionWithSideEffect);
System.out.println(String.join(", ", stringList));
最佳答案
在我看来,解决此问题的最干净方法是编写自定义拆分器并在其上创建Stream。如果您不需要绝对最大的性能并且不关心并行处理(并行流可以工作,但是效率很低),这并不是很难。这样的事情会起作用:
public static <T, R> Stream<R> pairMap(BaseStream<T, ?> source,
BiFunction<? super T, ? super T, ? extends R> mapper) {
Spliterator<T> spltr = source.spliterator();
long sourceSize = spltr.estimateSize();
Spliterator<R> result = new Spliterators.AbstractSpliterator<R>(
sourceSize > 0 && sourceSize < Long.MAX_VALUE ? sourceSize - 1 : sourceSize,
spltr.characteristics() & (Spliterator.ORDERED | Spliterator.SIZED)) {
T prev;
boolean started;
@Override
public boolean tryAdvance(Consumer<? super R> action) {
if (!started) {
if (!spltr.tryAdvance(t -> prev = t))
return false;
started = true;
}
return spltr.tryAdvance(t -> action.accept(mapper.apply(prev, prev = t)));
}
};
return StreamSupport.stream(result, source.isParallel()).onClose(source::close);
}
此处
mapper
是根据输入流的一对相邻元素创建新流的元素的函数。用法示例:
pairMap(IntStream.range(0, 6), (a, b) -> a + ", " + b).forEach(System.out::println);
输出:
0, 1
1, 2
2, 3
3, 4
4, 5