IntStream
Versuchen Sie für die spezielle Frage, eine Umkehrung zu generieren , Folgendes:
static IntStream revRange(int from, int to) {
return IntStream.range(from, to)
.map(i -> to - i + from - 1);
}
Dies vermeidet Boxen und Sortieren.
Bei der allgemeinen Frage, wie ein Stream eines beliebigen Typs umgekehrt werden kann, weiß ich nicht, dass es einen "richtigen" Weg gibt. Ich kann mir ein paar Möglichkeiten vorstellen. Beide speichern am Ende die Stream-Elemente. Ich kenne keine Möglichkeit, einen Stream umzukehren, ohne die Elemente zu speichern.
Auf diese erste Weise werden die Elemente in einem Array gespeichert und in umgekehrter Reihenfolge in einen Stream ausgelesen. Da wir den Laufzeittyp der Stream-Elemente nicht kennen, können wir das Array nicht richtig eingeben, was eine ungeprüfte Umwandlung erfordert.
@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]);
}
Bei einer anderen Technik werden die Elemente mithilfe von Sammlern in einer umgekehrten Liste zusammengefasst. Dadurch werden viele Einfügungen an der Vorderseite von ArrayList
Objekten vorgenommen, sodass viel kopiert wird.
Stream<T> input = ... ;
List<T> output =
input.collect(ArrayList::new,
(list, e) -> list.add(0, e),
(list1, list2) -> list1.addAll(0, list2));
Es ist wahrscheinlich möglich, einen viel effizienteren Umkehrkollektor mit einer angepassten Datenstruktur zu schreiben.
UPDATE 29.01.2016
Da diese Frage in letzter Zeit etwas Beachtung gefunden hat, sollte ich meine Antwort aktualisieren, um das Problem mit dem Einfügen vorne zu lösen ArrayList
. Dies ist bei einer großen Anzahl von Elementen schrecklich ineffizient und erfordert das Kopieren von O (N ^ 2).
Es ist vorzuziehen, ArrayDeque
stattdessen ein zu verwenden, das das Einsetzen an der Vorderseite effizient unterstützt. Eine kleine Falte ist, dass wir die Drei-Argumente-Form von nicht verwenden können Stream.collect()
; Es erfordert, dass der Inhalt des zweiten Args mit dem ersten Arg zusammengeführt wird, und es gibt keine Massenoperation "Alles an der Vorderseite hinzufügen" Deque
. Stattdessen addAll()
hängen wir den Inhalt des ersten Arguments an das Ende des zweiten an und geben dann das zweite zurück. Dies erfordert die Verwendung der Collector.of()
Factory-Methode.
Der vollständige Code lautet:
Deque<String> output =
input.collect(Collector.of(
ArrayDeque::new,
(deq, t) -> deq.addFirst(t),
(d1, d2) -> { d2.addAll(d1); return d2; }));
Das Ergebnis ist ein Deque
statt eines List
, aber das sollte kein großes Problem sein, da es leicht in der jetzt umgekehrten Reihenfolge iteriert oder gestreamt werden kann.
IntStream
hat keine.sorted(Comparator)
Methode; Sie müssen eine durchStream<Integer>
dort erste und umgekehrt eine vor nachgebendIntStream