2014-04-09 18 views
7

Tôi đang cố gắng triển khai phương pháp hợp nhất các giá trị trong hai số Stream s dựa trên giá trị Comparator cho các giá trị.Hợp nhất hai luồng

Tôi có cách để làm điều này, nơi tôi lặp qua các luồng và chèn các giá trị vào một Stream.Builder, nhưng tôi đã không thể tìm ra cách tạo phiên bản được đánh giá lười biếng (cách hoạt động của nhiều luồng), vì vậy nó cũng có thể xử lý các luồng vô hạn.

Tất cả tôi muốn nó phải làm là thực hiện một đơn sáp nhập vượt qua trên các dữ liệu đầu vào, không loại các dòng (trên thực tế, có khả năng là các con suối sẽ bị rối loạn; rối loạn này cần phải được bảo quản) .

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

Làm cách nào để tôi có thể hợp nhất hai luồng như thế này?

Nếu tôi được làm điều này với hai Queue s như là đầu vào và một số Consumer như đầu ra, nó sẽ là khá đơn giản:

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

Nhưng tôi cần phải làm điều này với đánh giá lười biếng, và suối.

Để giải quyết những ý kiến, đây là một số nguyên liệu đầu vào ví dụ và kết quả:

Ví dụ 1:

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

sẽ trả về một dòng mà sẽ tạo ra chuỗi này:

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

Ví dụ 2:

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

sẽ trả về một vô hạn (tốt, một mục INT_MAX + 5) dòng đó sẽ tạo ra chuỗi:

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

Như bạn có thể thấy, đây không phải là chỉ đơn thuần concat(first,second).sort(), vì (a) bạn không thể loại suối vô hạn, và (b) ngay cả khi bạn có thể sắp xếp các luồng, nó không đưa ra kết quả mong muốn.

+1

Bạn có thể không thực sự hợp nhất chúng từ đó, trừ trường hợp câu hỏi của bạn không cho nó tất cả, không ai trong số các con suối ban đầu đều được sắp xếp; có nghĩa là bạn không thể biết trước liệu phần tử đọc từ luồng 1 có nên được cho ăn hiệu quả trước một phần tử khác từ cùng một luồng đó hay không và bạn có cùng vấn đề với luồng 2. Bạn có thực sự mong đợi một giải pháp tồn tại ngoài việc nuốt cả hai và sắp xếp? – fge

+3

Ngoài 'Stream.concat (thứ nhất, thứ hai) .sorted (c);' Tôi không chắc chắn bạn có thể làm nhiều ... – assylias

+0

Tôi thực sự không hiểu điều này được cho là đang làm gì. @AJMansfield, bạn có thể đưa ra một ví dụ đầu vào và đầu ra về những gì bạn mong đợi không? Tùy thuộc vào ý của bạn, điều này có thể không phải là vô vọng, nhưng tôi không thể nói. Bạn có ý nghĩa gì khi "hợp nhất" luồng? Nếu nó, như, một sáp nhập hợp nhất từ ​​nhập khẩu được sắp xếp, nó hoàn toàn khả thi. –

Trả lời

6

Bạn cần triển khai Spliterator, thay vì xem qua Stream.Builder. Đối với điều này, bạn thậm chí có thể chỉ cần đi qua một Iterator, vì nó là một hoạt động khá tuần tự. Sử dụng ổi nhẹ,

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

Tôi phải thiếu một cái gì đó nhưng tôi không thấy làm thế nào điều này giải quyết vấn đề của OP? – fge

+0

Với giải thích được cập nhật bởi OP, đây là một câu trả lời đúng. –

+2

Không nên là 'Spliterator.ORDERED'? –