Вопрос или проблема
У меня есть следующий массив на входе
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. Это позволяет обрабатывать данные более элегантно и эффективно. Давайте рассмотрим, как реализовать данную задачу с учетом всех нюансов, указанных в вашем запросе.
Пошаговое Решение
- Работа с массивом строк: Начнем с того, что у нас есть массив строк, содержащий предложения с потенциально лишними пробелами и различным регистром.
String[] input = new String[] {
"This is a sample string",
" string ", // дополнительные пробелы здесь создают проблемы при разбиении
"Another sample string",
"This is not a sample string"
};
-
Использование Stream API: Вместо того, чтобы сначала объединять строки в одну, мы можем использовать поток, чтобы обработать каждую строку по отдельности. Это позволит избежать временных затрат на создание промежуточной строки.
-
Разбиение строк на слова: Вместо использования простого разбиения по пробелам, мы можем воспользоваться регулярным выражением
\\s+
, чтобы корректно обрабатывать последовательности пробелов. -
Согласованность регистра: Мы можем приводить все слова к одному регистру, что позволит избежать множественной записи одних и тех же слов с различным регистром.
-
Сбор частот: Наконец, мы используем
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 позволяет значительно упростить код и сделать его более читаемым. Применение регулярных выражений для разбиения строк по пробелам, а также преобразование к единому регистру обеспечивает корректность подсчетов. Подход, использующий потоки, делает код более декларативным и уменьшает вероятность ошибок.
Если у вас возникнут дополнительные вопросы или потребуется помощь в дальнейшем, не стесняйтесь обращаться!