Jeśli chodzi o konkretną kwestię generowania rewersu IntStream
, spróbuj czegoś takiego:
static IntStream revRange(int from, int to) {
return IntStream.range(from, to)
.map(i -> to - i + from - 1);
}
Pozwala to uniknąć boksowania i sortowania.
Jeśli chodzi o ogólne pytanie, jak odwrócić strumień dowolnego typu, nie wiem, czy istnieje „właściwy” sposób. Mogę wymyślić kilka sposobów. Oba kończą się przechowywaniem elementów strumienia. Nie znam sposobu na odwrócenie strumienia bez przechowywania elementów.
Ten pierwszy sposób zapisuje elementy w tablicy i odczytuje je do strumienia w odwrotnej kolejności. Zwróć uwagę, że ponieważ nie znamy typu środowiska wykonawczego elementów strumienia, nie możemy poprawnie wpisać tablicy, co wymaga niezaznaczonego rzutowania.
@SuppressWarnings("unchecked")
static <T> Stream<T> reverse(Stream<T> input) {
Object[] temp = input.toArray();
return (Stream<T>) IntStream.range(0, temp.length)
.mapToObj(i -> temp[temp.length - i - 1]);
}
Inna technika wykorzystuje kolekcjonerów do gromadzenia elementów w odwróconej liście. To powoduje wiele wstawek z przodu ArrayList
obiektów, więc jest dużo kopiowania.
Stream<T> input = ... ;
List<T> output =
input.collect(ArrayList::new,
(list, e) -> list.add(0, e),
(list1, list2) -> list1.addAll(0, list2));
Prawdopodobnie jest możliwe napisanie znacznie bardziej wydajnego kolektora wstecznego przy użyciu jakiejś niestandardowej struktury danych.
UPDATE 2016-01-29
Ponieważ ostatnio zwrócono uwagę na to pytanie, myślę, że powinienem zaktualizować swoją odpowiedź, aby rozwiązać problem z wstawianiem z przodu ArrayList
. Będzie to okropnie nieefektywne przy dużej liczbie elementów, wymagającym kopiowania O (N ^ 2).
Lepiej jest użyć ArrayDeque
zamiast tego, który skutecznie wspiera wkładanie z przodu. Mała zmarszczka polega na tym, że nie możemy użyć formy trójargumentowej Stream.collect()
; wymaga, aby zawartość drugiego argumentu została scalona z pierwszym argumentem i nie ma żadnej operacji zbiorczej typu „dodaj wszystko z przodu” Deque
. Zamiast tego addAll()
dodajemy zawartość pierwszego argumentu do końca drugiego, a następnie zwracamy drugi. Wymaga to użycia Collector.of()
metody fabrycznej.
Kompletny kod jest następujący:
Deque<String> output =
input.collect(Collector.of(
ArrayDeque::new,
(deq, t) -> deq.addFirst(t),
(d1, d2) -> { d2.addAll(d1); return d2; }));
Rezultatem jest a Deque
zamiast a List
, ale nie powinno to stanowić większego problemu, ponieważ można go łatwo iterować lub przesyłać strumieniowo w odwróconej kolejności.
IntStream
nie ma.sorted(Comparator)
metody; musisz przejść przezStream<Integer>
pierwszy i tam zawrócić, zanimIntStream