Получите частоты слов из массива строковых предложений с помощью Java 8

Вопрос или проблема

У меня есть следующий массив на входе

String[] input = new String[] {
       "Это пример строки",
       " строка ",                   // дополнительные пробелы здесь вызывают проблемы при разбиении
       "Другой пример строки",
       "Это не    пример строки"
};

Мне нужно подсчитать частоту отдельных слов. Требуемый вывод:

{a=2, не=1, строка=4, Это=2, есть=2, пример=3, Другой=1}

Пока что у меня есть несколько работающий код:

// 1. Преобразовать String[] в единую строку, разделенную " "
String joined = String.join(" ", input);

// 2. Разбить по " " и затем посчитать с использованием Collectors.groupingBy
Map <String, Long> output = Arrays.stream(joined.split(" "))
        .filter(s -> !s.equals(""))    // Для обработки пустых строк
        .collect(Collectors.groupingBy(Function.identity(),Collectors.counting()));

System.out.println(output);

Это выглядит очень грубо, пожалуйста, предложите лучший способ сделать это, используя Streams API.

Вы также можете объединить два шага, которые у вас есть, в один, то есть вместо объединения входного массива и разбиения после этого, вы можете выполнять потоковую обработку массива и выполнять задачу в одном конвейере:

Map<String, Long> output = Arrays.stream(input)
                                 .map(String::trim)
                                 .flatMap(s -> Pattern.compile("\\s+").splitAsStream(s))
                                 .map(String::toLowerCase)
                                 .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

Ваш код выглядит в целом корректно, несколько изменений сделают его работающим. Используйте String.split("\\s+") для разделения по любой последовательности пробельных символов вместо разделения по пробелу joined.split(" "). И с текущим кодом любые слова с учетом регистра будут рассматриваться как два разных слова, например Sample и sample, так что либо преобразуйте все в верхний или нижний регистр, если вы хотите получить количество без учета регистра

 Map<String, Long> output = Arrays.stream(joined.split("\\s+"))
        .map(String::toLowerCase) // Для преобразования без учета регистра, если это необходимо
        .filter(s -> !s.isEmpty()) // Исключить пустые строки 
        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

.

Ответ или решение

Чтобы подсчитать частоту слов в массиве строк с использованием Java 8, можно воспользоваться функциональным подходом с использованием Stream API. Это позволяет обрабатывать данные более элегантно и эффективно. Давайте рассмотрим, как реализовать данную задачу с учетом всех нюансов, указанных в вашем запросе.

Пошаговое Решение

  1. Работа с массивом строк: Начнем с того, что у нас есть массив строк, содержащий предложения с потенциально лишними пробелами и различным регистром.
String[] input = new String[] {
    "This is a sample string",
    " string ",                   // дополнительные пробелы здесь создают проблемы при разбиении
    "Another sample string",
    "This is not    a sample string"
};
  1. Использование Stream API: Вместо того, чтобы сначала объединять строки в одну, мы можем использовать поток, чтобы обработать каждую строку по отдельности. Это позволит избежать временных затрат на создание промежуточной строки.

  2. Разбиение строк на слова: Вместо использования простого разбиения по пробелам, мы можем воспользоваться регулярным выражением \\s+, чтобы корректно обрабатывать последовательности пробелов.

  3. Согласованность регистра: Мы можем приводить все слова к одному регистру, что позволит избежать множественной записи одних и тех же слов с различным регистром.

  4. Сбор частот: Наконец, мы используем Collectors.groupingBy и Collectors.counting для подсчета частоты встречаемости каждого слова.

Полный Код

Вот окончательный вариант кода, который выполняет поставленную задачу:

import java.util.Arrays;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.function.Function;
import java.util.stream.Collectors;

public class WordFrequency {
    public static void main(String[] args) {
        String[] input = new String[] {
            "This is a sample string",
            " string ",                   // дополнительные пробелы здесь создают проблемы при разбиении
            "Another sample string",
            "This is not    a sample string"
        };

        Map<String, Long> output = Arrays.stream(input)
            .flatMap(s -> Pattern.compile("\\s+").splitAsStream(s.trim())) // Убираем лишние пробелы и разбиваем
            .filter(s -> !s.isEmpty())  // Отфильтровываем пустые строки
            .map(String::toLowerCase)    // Приводим к нижнему регистру для обеспечения согласованности
            .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); // Считаем частоту

        System.out.println(output); // Вывод результата
    }
}

Результат

Код приведет к следующему результату:

{a=2, not=1, string=4, this=2, is=2, sample=3, another=1}

Заключение

Использование Java 8 Stream API позволяет значительно упростить код и сделать его более читаемым. Применение регулярных выражений для разбиения строк по пробелам, а также преобразование к единому регистру обеспечивает корректность подсчетов. Подход, использующий потоки, делает код более декларативным и уменьшает вероятность ошибок.

Если у вас возникнут дополнительные вопросы или потребуется помощь в дальнейшем, не стесняйтесь обращаться!

Оцените материал
Добавить комментарий

Капча загружается...