Каким образом считывать строки с List и подсчитывать количество повторяющихся слов?

public String countWords(List<String> lines) { }

Это исходные данные. Необходимо реализовать метод. На входе идет List, где каждый элемент - строка в txt-файле. Подсчитать количество повторяющихся слов (не менее n раз за текст). Причем, откинуть слова меньшие за мин. размера слова - min, и те, что больше за максимальный - max. Все это должно быть реализовано без циклов и условных операторов. Полагаю,начинать нужно как-то так?

lines.stream().filter(i -> i.length() >=4)


Ответы (2 шт):

Автор решения: kami

Если на входе - строки, то приведенный вами код не будет соответствовать условию, ведь фильтровать надо по словам:

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(); // и на выходе получили количество слов, удовлетворяющее всем условиями.
→ Ссылка
Автор решения: Nowhere Man

Нужно разбить каждую строку на "слова", используя 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();
}
→ Ссылка