合并两个流

时间:2014-04-09 21:40:04

标签: java merge java-8 java-stream

我正在尝试实现一种方法,根据值Stream合并两个Comparator中的值。

我有办法做到这一点,我遍历流并将值插入Stream.Builder,但我无法弄清楚如何制作延迟评估的版本(许多方式)流操作是),因此它也可以处理无限流。

我想要它做的就是对输入数据执行合并传递,对流进行排序(事实上,很可能流将是紊乱;这种疾病需要保留。)

static Stream<E> merge(Stream<E> first, Stream<E> second, Comparator<E> c)

我如何懒惰地合并这样的两个流?

如果我使用两个Queue作为输入并使用一些Consumer作为输出,那么这将非常简单:

void merge(Queue<E> first, Queue<E> second, Consumer<E> out, Comparator<E> c){
    while(!first.isEmpty() && !second.isEmpty()
        if(c.compare(first.peek(), second.peek()) <= 0)
            out.accept(first.remove());
        else
            out.accept(second.remove());
    for(E e:first)
        out.accept(e);
    for(E e:second)
        out.accept(e);
}

但是我需要使用惰性评估和流来完成这项工作。

为了解决这些评论,下面是一些示例输入和结果:

示例1:

merge(
    Stream.of(1, 2, 3, 1, 2, 3),
    Stream.of(2, 2, 3, 2, 2, 2),
    Comparator.naturalOrder()
);

会返回一个生成此序列的流:

1, 2, 2, 2, 3, 3, 1, 2, 2, 2, 2, 3

示例2:

merge(
    Stream.iterate(5, i->i-1),
    Stream.iterate(1, i->i+1),
    Comparator.naturalOrder()
);

将返回一个无限(好的,INT_MAX + 5项)流,它将生成序列:

1, 2, 3, 4, 5, 5, 4, 3, 2, 1, 0, -1 ...

正如您所看到的,这不仅仅是concat(first,second).sort(),因为(a)您无法对无限流进行排序,并且(b)即使您可以对流进行排序,也无法提供所需的结果。

2 个答案:

答案 0 :(得分:9)

您需要实施Spliterator,而不是通过Stream.Builder。为此,您甚至可以通过Iterator,因为它是一个相当顺序的操作。轻轻地使用番石榴,

return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
    Iterators.mergeSorted(
      Arrays.asList(stream1.iterator(), stream2.iterator()),
      comparator),
    Spliterator.ORDERED),
  false /* not parallel */ );

答案 1 :(得分:0)

番石榴的Iterables.mergeSorted()

public static <T> Iterable<T> mergeSorted(Iterable<? extends Iterable<? extends T>> iterables,
                Comparator<? super T> comparator)