2014-04-09 4 views
7

Ich versuche, eine Methode zu implementieren, um die Werte in zwei Stream s basierend auf einem Comparator für die Werte zusammenzuführen.Zwei Ströme zusammenführen

Ich hatte eine Möglichkeit, dies zu tun, wo ich über die Streams iterieren und die Werte in eine Stream.Builder einfügen, aber ich konnte nicht herausfinden, wie eine Lazy-ausgewertete Version (wie viele Stream-Operationen sind)), so kann es auch mit unendlichen Strömen umgehen.

Alles, was ich will es einen Einzel verschmelzenden Pass auf den Eingangsdaten tun durchführen, nicht sortiert die Ströme (in der Tat ist es wahrscheinlich, dass die Ströme ungeordnet sein werden, diese Störung muss erhalten bleiben) .

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

Wie kann ich zwei Ströme so zusammenführen?

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); 
} 

Aber ich brauche diese mit lazy evaluation zu tun, und Bächen:

Wenn ich mit zwei Queue s als Eingang und einig Consumer als Ausgang tat dies, wäre es ziemlich einfach sein.

die Kommentare zu adressieren, sind hier einige Beispiel-Eingänge und das Ergebnis:

Beispiel 1:

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

würde einen Stream zurück, die diese Sequenz erzeugen würde:

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

Beispiel 2:

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

würde eine unendliche (na ja, ein INT_MAX + 5 Artikel) Strom zurück, die die Sequenz erzeugen würde:

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

Wie Sie sehen können, ist dies nicht nur ist concat(first,second).sort(), da (a) Sie können nicht sortieren unendliche Ströme, und (b) selbst wenn Sie die Ströme sortieren können, gibt es nicht das gewünschte Ergebnis.

+1

Sie können sie nicht wirklich zusammenführen, da, wenn Ihre Frage nicht alles sagt, keiner der ursprünglichen Ströme sortiert werden; Das bedeutet, dass Sie nicht im Voraus wissen können, ob das aus Stream 1 zu lesende Element effektiv vor einem anderen Element aus demselben Stream gefüttert werden soll, und Sie haben das gleiche Problem mit Stream 2. Haben Sie ernsthaft eine Lösung erwartet, abgesehen davon, dass Sie beide verschlingen und sortieren? – fge

+3

Abgesehen von 'Stream.concat (erste, zweite) .sorted (c);' Ich bin mir nicht sicher, ob Sie viel tun können ... – assylias

+0

Ich verstehe wirklich nicht, was das tun soll. @AJMansfield, können Sie ein Eingabe- und Ausgabe-Beispiel für das geben, was Sie erwarten? Je nachdem, was du meinst, ist das vielleicht nicht so hoffnungslos, aber ich kann es nicht sagen. Was meinst du damit, den Stream "zusammenzuführen"? Wenn es sich beispielsweise um einen Mergesort-Merge aus dem sortierten Import handelt, ist es machbar. –

Antwort

6

Sie müssen Spliterator implementieren, anstatt Stream.Builder zu durchlaufen. Dazu können Sie sogar einfach eine Iterator durchlaufen, da es eine ziemlich sequenzielle Operation ist. Mit Guava leicht,

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

Ich muss etwas vermissen, aber ich sehe nicht, wie dies das Problem des OP löst? – fge

+0

Angesichts der aktualisierten Erklärung des OP ist dies in der Tat eine richtige Antwort. –

+2

Sollte es nicht 'Spliterator.ORDERED' sein? –