问题
Suppose we have a collection (or stream?)
{"1","2","3","4"...}
now we want to take two elements and compose a pair like this
{{"1","2"}, {"2","3"},{"3","4"}..}
We know how to do that the ugly way (for loop).
I wonder how do we do this with java 8 streams?
Because approaches in java streams and reactive extensions are pretty much same (both are monads) I thought there might be something alike RX .pick(2)
which would trigger event when 2 elements arrive...
回答1:
It's not pretty either but you can do it with a collector. I've used an ArrayList with Arrays inside, but you can use different intermediate collection types if you want.
What I've done here is a collector that adds every item as a second item on the last array added to the accumulator and as a first item on a new array that will be added to the accumulator.
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
ArrayList<Integer[]> pairs =
stream.collect(
() -> new ArrayList<>(),
(acc, next) -> {
if(acc.isEmpty()) {
acc.add(new Integer[] {next, null});
} else {
acc.get(acc.size() - 1)[1] = next;
acc.add(new Integer[] {next, null});
}
},
ArrayList::addAll
);
pairs.forEach(a -> System.out.println(a[0] + ", " + a[1]));
//-> 1, 2
//-> 2, 3
//-> 3, 4
//-> 4, 5
//-> 5, 6
//-> 6, null
回答2:
It is possible to use the IntStream.range
to loop in a stream-kind-of-way.
String[] str = {"1", "2", "3", "4"};
final String[][] result = IntStream.range(0, str.length - 1)
.mapToObj(i -> new String[]{str[i], str[i + 1]})
.toArray(String[][]::new);
The result contains {{"1", "2"}, {"2", "3"}, {"3", "4"}}
.
来源:https://stackoverflow.com/questions/28622119/pick-2-elements-from-stream-at-a-time