Перепись вложенного цикла Stream API
Имеется код, который нужно переписать с использованием Stream API. Подскажите, как это можно сделать?
Моя попытка это реализовать:
text.getComponents()
.stream()
.flatMap(p -> p.getComponents()
.stream()
.flatMap(s -> s.getComponents()
.stream()
.filter(l -> l.getType() != TextComponentType.PUNCTUATION)
.anyMatch(c -> c.getComponents().size() < min)
.forEach((p.getComponents().remove(s));
Код самого цикла:
for (TextComponent paragraph : text.getComponents()) {
for (TextComponent sentence : paragraph.getComponents()) {
int numberOfWord = 0;
for (TextComponent lexeme : sentence.getComponents()) {
if (lexeme.getType() != TextComponentType.PUNCTUATION) {
numberOfWord++;
}
}
if (numberOfWord < min) {
paragraph.removeText(sentence);
}
}
}
Ответы (1 шт):
Не уверен, что в данном случае применение Stream API оправдано, так как фактически должны применяться вложенные forEach операции. Впрочем, и удаление предложений из параграфа во время итерации по коллекции предложений в версии с циклами вполне способно вызвать ConcurrentModificationException.
Лобовое решение на стримах может выглядеть так:
text.getComponents().stream().forEach(
parag -> parag.getComponents().stream() // поток предложений
.filter(s -> s.getComponents().stream() // поток лексем
.filter(lex -> lex.getType() != TextComponentType.PUNCTUATION)
.count() < min
) // отфильтрованный поток предложений
.forEach(parag::removeText)
);
Более корректным решением может быть сначала определить список предложений, подлежащих удалению, а потом уже удалять их
text.getComponents().stream().forEach(
parag -> {
List<TextComponent> shortSentences = parag.getComponents()
.stream() // поток предложений
.filter(s -> s.getComponents().stream() // поток лексем
.filter(lex -> lex.getType() != TextComponentType.PUNCTUATION)
.count() < min
) // отфильтрованный поток предложений
.collect(Collectors.toList());
shortSentences.forEach(parag::removeText);
// или parag.getComponents().removeAll(shortSentences) если такое допустимо
}
);
Ещё один вариант -- удалять элементы из коллекции TextComponent, используя removeIf, если это допускается в данной реализации, т.е. коллекция модифицируема -- Stream API здесь применяется частично
text.getComponents().forEach(
p -> p.getComponents().removeIf(
s -> s.getComponents().stream()
.filter(lex -> lex.getType() != TextComponentType.PUNCTUATION)
.count() < min
)
);