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 ArrayListoggetti, 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 ArrayDequeinvece 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 è Dequeinvece di a List, ma non dovrebbe essere un grosso problema, in quanto può essere facilmente ripetuto o riprodotto in streaming nell'ordine ora invertito.
IntStreamnon ha.sorted(Comparator)metodo; si deve passare attraverso unaStream<Integer>prima e retromarcia non prima di cedere unIntStream