Per la domanda specifica di generare un contrario IntStream
, prova qualcosa del genere:
static IntStream revRange(int from, int to) {
return IntStream.range(from, to)
.map(i -> to - i + from - 1);
}
Ciò evita la boxe e l'ordinamento.
Per la domanda generale su come invertire uno stream di qualsiasi tipo, non so se esiste un modo "corretto". Ci sono un paio di modi a cui riesco a pensare. Entrambi finiscono per memorizzare gli elementi del flusso. Non conosco un modo per invertire un flusso senza memorizzare gli elementi.
Questo primo modo memorizza gli elementi in un array e li legge in un flusso in ordine inverso. Si noti che poiché non conosciamo il tipo di runtime degli elementi stream, non possiamo digitare l'array correttamente, richiedendo un cast non controllato.
@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]);
}
Un'altra tecnica utilizza i collezionisti per accumulare gli oggetti in un elenco invertito. Questo fa molti inserimenti nella parte anteriore degli ArrayList
oggetti, quindi ci sono molte copie in corso.
Stream<T> input = ... ;
List<T> output =
input.collect(ArrayList::new,
(list, e) -> list.add(0, e),
(list1, list2) -> list1.addAll(0, list2));
Probabilmente è possibile scrivere un raccoglitore d'inversione molto più efficiente usando una sorta di struttura dati personalizzata.
AGGIORNAMENTO 2016-01-29
Dato che questa domanda ha attirato un po 'di attenzione di recente, immagino che dovrei aggiornare la mia risposta per risolvere il problema con l'inserimento in primo piano ArrayList
. Questo sarà orribilmente inefficiente con un gran numero di elementi, che richiederà la copia di O (N ^ 2).
È preferibile utilizzare ArrayDeque
invece un , che supporta in modo efficiente l'inserimento nella parte anteriore. Una piccola ruga è che non possiamo usare la forma a tre argomenti di Stream.collect()
; richiede che i contenuti del secondo arg siano uniti nel primo arg, e non ci sono operazioni di massa "add-all-at-front" su Deque
. Invece, usiamo addAll()
per aggiungere il contenuto del primo argomento alla fine del secondo, e quindi restituiamo il secondo. Ciò richiede l'utilizzo del Collector.of()
metodo di fabbrica.
Il codice completo è questo:
Deque<String> output =
input.collect(Collector.of(
ArrayDeque::new,
(deq, t) -> deq.addFirst(t),
(d1, d2) -> { d2.addAll(d1); return d2; }));
Il risultato è Deque
invece di a List
, ma non dovrebbe essere un grosso problema, in quanto può essere facilmente ripetuto o riprodotto in streaming nell'ordine ora invertito.
IntStream
non ha.sorted(Comparator)
metodo; si deve passare attraverso unaStream<Integer>
prima e retromarcia non prima di cedere unIntStream