How can I extract two elements from a Stream by their positions? For example I'm trying to extract element 0 and 1 (these numbers are arbitrary!) from a Stream<String>
. A naive approach is this:
List<String> strings = Arrays.asList("s0", "s1", "s2", "s3", "s4");
Consumer<String> c0 = s -> System.out.println("c0.accept(" + s + ")");
Consumer<String> c1 = s -> System.out.println("c1.accept(" + s + ")");
strings.stream().skip(0).peek(c0).skip(1).peek(c1).findAny();
This produces the following output:
c0.accept(s0)
c0.accept(s1)
c1.accept(s1)
I understand that it's because s0
will enter the stream, encounter skip(0)
, then peek(c0)
(which gives the the first line) and then skip(1)
, which will skip this element and then apparently continue with the next element from the beginning of the stream.
I thought I could use these consumers to extract the strings, but c0
would be overwritten by the second element:
String[] extracted = new String[2];
c0 = s -> extracted[0];
c1 = s -> extracted[1];
EDIT:
These are the characteristics of the stream:
Using Stream findFirst() Method: The findFirst() method will returns the first element of the stream or an empty if the stream is empty. Approach: Get the stream of elements in which the first element is to be returned. To get the first element, you can directly use the findFirst() method.
Given your restriction you can combine the limit()
with custom collector like this:
public static <T, A, R> Collector<T, ?, R> collectByIndex(Set<Integer> wantedIndices,
Collector<T, A, R> downstream) {
class Acc {
int pos;
A acc = downstream.supplier().get();
}
return Collector.of(Acc::new, (acc, t) -> {
if(wantedIndices.contains(acc.pos++))
downstream.accumulator().accept(acc.acc, t);
}, (a, b) -> {throw new UnsupportedOperationException();}, // combining not supported
acc -> downstream.finisher().apply(acc.acc));
}
Here Set<Integer> wantedIndices
is the set containing the indices of wanted elements (not limited by 2). Usage:
Set<Integer> wantedIndices = new HashSet<>(Arrays.asList(1, 3));
Stream<String> input = Stream.of("s0", "s1", "s2", "s3", "s4");
List<String> result = input.limit(Collections.max(wantedIndices)+1)
.collect(collectByIndex(wantedIndices, Collectors.toList()));
// [s1, s3]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With