Преобразование потока <IntStream>в один IntStream - PullRequest
0 голосов
/ 09 марта 2019

Я хочу преобразовать List<String> в IntStream. Предположим, что мой список похож на ["abc", "de", "fghi"]. Тогда IntStream, который я хочу, похож на 1,1,1,2,2,3,3,3,3. (Количество вхождений числа i в IntStream зависит от длины i -ой строки в данном списке)

Я написал для этого следующий метод (он не скомпилируется):

private static IntStream getSingleIntStream(List<String> list) {
    final AtomicInteger atomicInteger = new AtomicInteger();
    return list.stream()
            .map(str -> {
                        atomicInteger.incrementAndGet();
                        return IntStream.range(0, str.length())
                                .map(i -> atomicInteger.get());
                    }); // Now I don't understand how can I convert this Stream<IntStream> to a single IntStream 

}

Но я не понимаю, как я могу преобразовать, могу ли я преобразовать Stream<IntStream> в один IntStream. (Я предполагаю, что мы можем как-то использовать flatMap, но я не совсем понимаю, как его использовать.)

Я использую IntStream вместо Stream<Integer>, чтобы избежать автоматической блокировки и повысить эффективность всей моей системы.

Ответы [ 4 ]

6 голосов
/ 09 марта 2019

Другое решение будет выглядеть так:

IntStream result =  IntStream.range(0,list.size())
                             .flatMap(i-> IntStream.range(0, list.get(i)
                                                                 .length())
                                                   .map(j->i+1));
2 голосов
/ 09 марта 2019

Расширение комментария @ JB_Nizet

Мне нужно использовать метод flatMapToInt .

private static IntStream getSingleIntStream(List<String> list) {
    final AtomicInteger atomicInteger = new AtomicInteger();
    return list.stream()
            .flatMapToInt(str -> {
                atomicInteger.incrementAndGet();
                return IntStream.range(0, str.length())
                        .map(i -> atomicInteger.get());
            });
}
1 голос
/ 10 марта 2019

Вы абсолютно правы относительно flatMap, как Хади J уже показывает в хорошем ответе. Я просто хотел предложить свой вариант такой же:

private static IntStream getSingleIntStream(List<String> list) {
    return IntStream.rangeClosed(1, list.size())
            .flatMap(i -> list.get(i - 1).chars().map(ch -> i));
}

Вы можете найти эту версию более естественной или краткой. В любом случае обе версии имеют то преимущество, что избегают AtomicInteger и побочного воздействия потокового конвейера на него. Потоковый конвейер не должен иметь побочных эффектов.

Давайте также посмотрим на это в действии:

    List<String> list = List.of("abc", "de", "fghi");
    int[] nums = getSingleIntStream(list).toArray();
    System.out.println(Arrays.toString(nums));

[1, 1, 1, 2, 2, 3, 3, 3, 3]

Когда вам нужен индекс элемента внутри потока, общий прием заключается в том, чтобы начинать с IntStream индексов, а внутри вашего потокового конвейера производить поиск элементов из индексов (list.get(i - 1)). В этом случае я (нетрадиционно) использую индексы, основанные на 1, потому что вы хотели, чтобы ваши результирующие числа начинались с 1. Поэтому нам нужно вычесть 1 в поиске по списку.

1 голос
/ 09 марта 2019

Решение будет использовать flatMapToInt:

private static IntStream getSingleIntStream(List<String> list) {
    final AtomicInteger atomicInteger = new AtomicInteger();
    return list.stream()
        .flatMapToInt(str -> {
            atomicInteger.incrementAndGet();
            return IntStream.range(0, str.length())
                .map(i -> atomicInteger.get());
        });
}

но я бы переосмыслил то, чего вы хотели бы достичь здесь. Теперь каждый String в исходном списке будет заменен числом, взятым из AtomicInteger (и это будет повторяться String.length () раз для каждой строки):

getSingleIntStream(Arrays.asList("a", "bc")).forEach(System.out::println); // 1 2 2

Я полагаю, что вы хотите пронумеровать каждый символ из каждого String:

private static IntStream getSingleIntStream(List<String> list) {
    AtomicInteger atomicInteger = new AtomicInteger();
    return list.stream()
        .flatMapToInt(str -> IntStream.range(0, str.length())
            .map(i -> atomicInteger.incrementAndGet()));
}

// 1 2 3
...