Каким образом считывать строки с List и подсчитывать количество повторяющихся слов?
public String countWords(List<String> lines) { }
Это исходные данные. Необходимо реализовать метод. На входе идет List, где каждый элемент - строка в txt-файле. Подсчитать количество повторяющихся слов (не менее n раз за текст). Причем, откинуть слова меньшие за мин. размера слова - min, и те, что больше за максимальный - max. Все это должно быть реализовано без циклов и условных операторов. Полагаю,начинать нужно как-то так?
lines.stream().filter(i -> i.length() >=4)
Ответы (2 шт):
Если на входе - строки, то приведенный вами код не будет соответствовать условию, ведь фильтровать надо по словам:
Long wordRepeatCounter = lines.stream()
.flatMap(line -> Arrays.stream(line.split(" "))) // делим на слова,
// считая что они разделены пробелами (хотя могут встречаться и tab, и неразрывный пробел и...)
.filter(word -> (word.length() >= minLength) && (word.length() <= maxLength)) // убираем лишние
.collect(
Collectors.toUnmodifiableMap( // собираем в Map
s->s, // ключ - само слово
s -> 1, // значение - количество повторений
Integer::sum)) // которое дополняем в методе "что делать с дубликатами"
.entrySet().stream()// тут имеем пары "слово":"количество повторений"
.filter(entry->entry.getValue()>minRepeatCount) // отсекаем те, у кого слишком мало повторений
.count(); // и на выходе получили количество слов, удовлетворяющее всем условиями.
Нужно разбить каждую строку на "слова", используя String.split -- в простейшем случае при помощи шаблона для разделителей "\W+", или выбирая "слова" при помощи противоположного шаблона "\w+", ипользуя операцию flatMap для получения потока слов, к которому уже можно применить необходимые фильтры по длине слова, затем подсчитать частоту слов, применяя Collectors.counting / Collectors.summingInt и дополнительно отфильтровать слова с нужной частотой:
public long countWords(List<String> lines, int min, int max, int n) {
return lines
.stream() // Stream<String> строки
.flatMap(s -> Arrays.stream(s.split("\\W+"))) // Stream<String> слова
.filter(w -> min <= w.length() && w.length() <= max)
.collect(Collectors.groupingBy(
w -> w, // ключ - слово
Collectors.counting() // значение - частота
)) // Map<String, Long>
.entrySet()
.stream() //Stream<Map.Entry<String, Long>>
.filter(e -> e.getValue() >= n)
.count();
}
Второй вариант, использующий метод Matcher::results, который возвращает Stream<MatchResult>, в свою очередь преобразуемый в поток слов при помощи MatchResult::group:
public long countWords(List<String> lines, int min, int max, int n) {
Pattern word = Pattern.compile("\\w+");
return lines
.stream() // Stream<String> строки
.flatMap(s -> word.matcher(s).results().map(MatchResult::group)) // Stream<String> слова
.filter(w -> min <= w.length() && w.length() <= max)
.collect(Collectors.groupingBy(
w -> w, // ключ - слово
Collectors.summingInt(w -> 1) // значение - частота
)) // Map<String, Integer>
.entrySet()
.stream() //Stream<Map.Entry<String, Integer>>
.filter(e -> e.getValue() >= n)
.count();
}