2016-05-26 8 views
8

Uzyskanie przecięcia dwóch strumieni lub sprawdzenie, czy ich przecięcie jest puste, czy też nie, jest generalnie niemożliwe w Javie, ponieważ strumienie można użyć tylko raz, a rozwiązanie ogólne ma złożoność O(m*n) .Ustalanie, czy przecięcie strumienia nie jest puste

Jeśli nie wiemy nic na temat charakteru bazowego dostawcy wiedzieć, możemy uciec z co najwyżej jednym strumieniu i jednej kolekcji:

<T> boolean intersects(final Stream<T> c1, final Collection<T> c2) { 
    return c1.filter(c2::contains).findAny().isPresent(); 
} 

Mimo to, co jeśli obie nasi dostawcy reprezentują zamówionej kolekcje posortowane przy użyciu tego samego komparatora (w najprostszym przypadku, dwa TreeSet s z Comparable s)? W takim przypadku rozwiązanie będzie miało złożoność liniową liniową (lub, bardziej precyzyjnie, O(m*n), patrz odpowiedź this).

Teraz pytanie wyżej liniowy rozwiązanie może być realizowane za pomocą tylko Strumień API (to jest za pomocą dwóch strumieni jako wejście.).?

+0

Czy pytasz, czy możesz wdrożyć rozwiązanie liniowe, jeśli dane w strumieniach są uporządkowane? –

+4

Rozwiązania iteracyjne i strumienie nie pasują do siebie, więc najlepszą rzeczą, jaką możesz zrobić, jest wywołanie 'iterator()' na strumieniach i kontynuowanie. – Holger

+0

@JimMischel Tak, dokładnie – Bass

Odpowiedz

7

można tylko zbierać drugi strumień do Set i zapytać, czy każdy element pierwszego Stream jest zawarty w tym zestawie:

<T> boolean intersects(final Stream<T> c1, final Stream<T> c2) { 
    return c1.anyMatch(c2.collect(Collectors.toSet())::contains); 
} 

Making zestaw z c1 jest liniowa w zakresie liczby elementy w nim, a contains jest operacją o stałym czasie.

+0

Dzięki, to jest dobre rozwiązanie i to pytanie, ponieważ nie ma ograniczeń co do wielkości pamięci. Mimo to oryginalne rozwiązanie iteracyjne (przesuwając jeden z dwóch iteratorów) nie wymaga dodatkowej pamięci, podczas gdy twój strumień działa. Czy możliwe jest rozwiązanie tego samego zadania w czasie liniowym bez wprowadzania nowych kolekcji? – Bass

+3

@ Krótka odpowiedź: nie. Długa odpowiedź: noooooo. Nie bez konwertowania strumieni z powrotem do iteratorów, w zasadzie. –

+2

@Bass Problem z posiadaniem iteratora polega na tym, że nie można łatwo "zerknąć" na element. Musisz go używać z 'next()', więc znacznie trudniej jest tylko przejść do jednego z dwóch iteratorów. – Tunaki