Выбрать (в виде списка) из текста все слова без повторений. Java

Рейтинг: -1Ответов: 1Опубликовано: 26.01.2023

В задачах, где необходимо выбрать что-то без повторений, удобным (и эффективным в плане быстродействия) будет использовать Set (HashSet или TreeSet) для хранения уже выбранных элементов.

Выбрать (в виде списка) из текста все слова без повторений, содержащие 3 и более одинаковые буквы. Разделителями слов считаются любые символы, отличные от букв А- Я, A-Z и цифр.

Ответы

▲ 0

Для поиска подходящих слов можно разбить строку на слова при помощи String::split, а затем отфильтровать слова при помощи String::matches с соответствующим регулярным выражением. Также можно искать слова при помощи заранее подготовленного шаблона для поиска трёх букв подряд и метода Matcher::find. Или же можно сразу искать подходящие слова в строке без String::split при помощи соответствующего шаблона.

При использовании Stream API есть способы получить список без дубликатов:

  • Stream::distinct
    Самый простой способ, но при нём слова разного регистра будут считаться разными
  • Собрать результат в сет, который затем скопируется в список
    Чтобы считать слова разного регистра одинаковыми (например, Aaa / AAA / aaa), можно собирать результат в TreeSet с компаратором String::CASE_INSENSITIVE_ORDER, при этом порядок вхождения слов в начальную строку будет нарушен, так как такой сет будет отсортирован по алфавиту
  • Собрать результат в мапу с одним значением (первым или последним вхождением) и добавить коллекцию значений в список
    Этот способ позволит сохранить порядок вхождения слов в начальной строке, игнорируя дубликаты в разном регистре

Пример решения: Pattern + Matcher.find + Collectors.toMap

static final Pattern THREE_LETTERS = Pattern.compile("([a-zа-яё])\\1{2}", Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);

public static List<String> withTriplets(String str) {
    return new ArrayList<>(Arrays
        .stream(str.split("[^a-zA-Zа-яА-ЯёЁ0-9]+"))
        //.filter(w -> w.matches("(?iu).*([a-zа-яё])\\1{2}.*"))
        .filter(w -> THREE_LETTERS.matcher(w).find())
        .collect(Collectors.toMap(
            String::toLowerCase, w -> w, (a, b) -> a, LinkedHashMap::new
        ))
        .values()
    );
}

Тест:

System.out.println(withTriplets("Бешеный зооОхранитель Пресссельхоза расстрелял длинношеее чудовище и скормил останки ручному змееЕду.  Длинношеее блюдо понравилось змеееду."));
[зооОхранитель, Пресссельхоза, длинношеее, змееЕду]