MC Emperor :
How can I perform multiple unrelated operations on elements of a single stream?
Say I have a List<String>
composed from a text. Each string in the list may or may not contain a certain word, which represents an action to perform. Let's say that:
- if the string contains 'of', all the words in that string must be counted
- if the string contains 'for', the portion after the first occurrence of 'for' must be returned, yielding a
List<String>
with all substrings
Of course, I could do something like this:
List<String> strs = ...;
List<Integer> wordsInStr = strs.stream()
.filter(t -> t.contains("of"))
.map(t -> t.split(" ").length)
.collect(Collectors.toList());
List<String> linePortionAfterFor = strs.stream()
.filter(t -> t.contains("for"))
.map(t -> t.substring(t.indexOf("for")))
.collect(Collectors.toList());
but then the list would be traversed twice, which could result in a performance penalty if strs
contained lots of elements.
Is it possible to somehow execute those two operations without traversing twice over the list?
Flown :
If you want a single pass Stream
then you have to use a custom Collector
(parallelization possible).
class Splitter {
public List<String> words = new ArrayList<>();
public List<Integer> counts = new ArrayList<>();
public void accept(String s) {
if(s.contains("of")) {
counts.add(s.split(" ").length);
} else if(s.contains("for")) {
words.add(s.substring(s.indexOf("for")));
}
}
public Splitter merge(Splitter other) {
words.addAll(other.words);
counts.addAll(other.counts);
return this;
}
}
Splitter collect = strs.stream().collect(
Collector.of(Splitter::new, Splitter::accept, Splitter::merge)
);
System.out.println(collect.counts);
System.out.println(collect.words);
Guess you like
Origin http://10.200.1.11:23101/article/api/json?id=465746&siteId=1