将Stream <intstream>转换为单个IntStream

时间:2019-03-09 08:21:57

标签: java java-8 java-stream

我想将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 个答案:

答案 0 :(得分:6)

另一个解决方案是这样的:

IntStream result =  IntStream.range(0,list.size())
                             .flatMap(i-> IntStream.range(0, list.get(i)
                                                                 .length())
                                                   .map(j->i+1));

答案 1 :(得分:2)

扩展@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());
            });
}

答案 2 :(得分:1)

解决方案是使用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都会重复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

答案 3 :(得分:1)

您对flatMap绝对是正确的,正如哈迪·J(Hadi 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个索引开始,然后在流管道内部从索引中查找元素({{1 }})。在这种情况下,我(非常规地)使用基于1的索引,因为您希望得到的数字从1开始。因此我们需要在列表查找中减去1。