用分隔符交错流中的元素

时间:2014-09-02 13:29:51

标签: java java-8 java-stream

有没有一种很好的方法可以使用Java流来交换流中的元素和相同类型的分隔符?

// Expected result in is list: [1, 0, 2, 0, 3]
List<Integer> is = Stream.of(1, 2, 3).intersperse(0).collect(toList()); 

这类似于Haskell和其他函数式语言中的intersperse函数。

我见过很多关于如何以类似的方式连接字符串但没有找到任何常规列表解决方案的例子。

2 个答案:

答案 0 :(得分:8)

你可以使用flatMap,但是你会在最后一个元素之后得到一个额外的分隔符:

List<Integer> is = IntStream.of(1, 2, 3)
                            .flatMap(i -> IntStream.of(i, 0))
                            .collect(toList());

这是另一种方式,没有尾随分隔符:

List<Integer> is = IntStream.of(1, 2, 3)
                            .flatMap(i -> IntStream.of(0, i))
                            .skip(1)
                            .collect(toList());

这次我们在每个原始元素之前添加分隔符,并去除前导分隔符。

答案 1 :(得分:6)

你可以用Collectors.joiningString做一个类似的事情,用一个小帮手方法:

static <T> Collector<T,List<T>,List<T>> intersperse(T delim) {
    return Collector.of(ArrayList::new, (l,e)-> {
        if(!l.isEmpty()) l.add(delim);
        l.add(e);
    }, (l,l2)-> {
        if(!l.isEmpty()) l.add(delim);
        l.addAll(l2);
        return l;
    });

然后您可以使用它类似于Collectors.joining(delimiter)

List<Integer> l=Stream.of(1, 2, 3).collect(intersperse(0));

产生

  

[1,0,2,0,3]

请注意,由于collect保护这些操作的方式,这是线程安全的。


如果您不想收集到列表但是将分隔符作为中间流操作插入,则可以这样做:

Integer delimiter=0;
Stream.of(1, 2, 3)/** or any other stream source */
      .map(Stream::of)
      .reduce((x,y)->Stream.concat(x, Stream.concat(Stream.of(delimiter), y)))
      .orElse(Stream.empty())
      /* arbitrary stream operations may follow */