Разделить список слов, используя потоки в Java

У меня есть этот метод, который принимает несколько списков, содержащих строки книг. Я расчесываю их в поток, чтобы затем перебрать их, чтобы разделить на все небуквенные \\P{L}.

Есть ли способ избежать цикла for-each и обработать его в потоке?

private List<String> getWordList(List<String>... lists) {
        List<String> wordList = new ArrayList<>();

        Stream<String> combinedStream = Stream.of(lists)
                .flatMap(Collection::stream);
        List<String> combinedLists = combinedStream.collect(Collectors.toList());

        for (String line: combinedLists) {
            wordList.addAll(Arrays.asList(line.split("\\P{L}")));
        }

        return wordList;
}
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
4
0
4 739
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Имея стрим можно просто "flatMap" дальше и вернуть результат:

return combinedStream
        .flatMap(str -> Arrays.stream(str.split("\\P{L}")))
        .collect(Collectors.toList());

Если выразиться вообще:

private List<String> getWordList(List<String>... lists) {
    return Stream.of(lists)
        .flatMap(Collection::stream)
        .flatMap(str -> Arrays.stream(str.split("\\P{L}")))
        .collect(Collectors.toList());
}

Вы можете объединить весь список и flatMap для результата

private List<String> getWordList(List<String>... lists) {
    return Stream.of(lists)
    .flatMap(Collection::stream)
    .flatMap(str -> Arrays.stream(str.split("\\P{L}")))
    .collect(Collectors.toList());
}
str здесь не строка, а List. Так что List.split() не может скомпилироваться. Вы пропустили промежуточную операцию: stackoverflow.com/a/54969149/270371
davidxxx 03.03.2019 14:12

Вам не нужно вводить так много переменных:

private List<String> getWordList(List<String>... lists) {

    return Stream.of(lists) // Stream<Stream<String>>
                 .flatMap(Collection::stream) // Stream<String> 
                 .flatMap(Pattern.compile("\\P{L}")::splitAsStream) //Stream<String>     
                 .collect(toList()); // List<String>
}

Как подчеркнул Хольгер, .flatMap(Pattern.compile("\\P{L}")::splitAsStream)
следует предпочесть .flatMap(s -> Arrays.stream(s.split("\\P{L}"))), чтобы сэкономить выделение массива и компиляцию шаблона, выполняемую для каждого элемента потока.

Как поясняется в этом ответе, рекомендуется использовать .flatMap(Pattern.compile("\\P{L}") ::splitAsStream), чтобы избежать повторной компиляции шаблона для каждого элемента потока и не заполнять потенциально большой промежуточный массив.

Holger 04.03.2019 12:13

@Holger Большое спасибо за эту ссылку. Я еще не видел этого из Java 8. Но мне не очень нравится ссылка на метод в этом случае (Pattern.splitAsStream(String), по крайней мере, для меня не используется), но, согласно вашему комментарию в другом посте, это требуется, и я его получаю. Мы также можем скомпилировать шаблон вне потока, но это тоже не страшно.

davidxxx 04.03.2019 17:34

Ну, вы также можете переместить шаблон в константу, например static final Pattern NON_LETTER_CHARS = Pattern.compile("\\P{L}");, а затем использовать либо .flatMap(NON_LETTER_CHARS::splitAsStream), либо .flatMap(s -> NON_LETTER_CHARS.splitAsStream(s)). В конце концов, вы также должны знать о механизме регулярных выражений при использовании s.split("\\P{L}").

Holger 04.03.2019 17:39

Действительно, это то, на что я ссылался в своем комментарии, извините. Это способ, но это не страшно.

davidxxx 04.03.2019 17:41

Другие вопросы по теме