Pour la question spécifique de la génération d'un reverse IntStream
, essayez quelque chose comme ceci:
static IntStream revRange(int from, int to) {
return IntStream.range(from, to)
.map(i -> to - i + from - 1);
}
Cela évite la mise en boîte et le tri.
Pour la question générale de savoir comment inverser un flux de n'importe quel type, je ne sais pas s'il existe un moyen "approprié". Je peux penser à plusieurs façons. Les deux finissent par stocker les éléments du flux. Je ne connais pas de moyen d'inverser un flux sans stocker les éléments.
Cette première méthode stocke les éléments dans un tableau et les lit dans un flux dans l'ordre inverse. Notez que puisque nous ne connaissons pas le type d'exécution des éléments de flux, nous ne pouvons pas taper le tableau correctement, ce qui nécessite un cast non vérifié.
@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]);
}
Une autre technique utilise des collectionneurs pour accumuler les éléments dans une liste inversée. Cela fait beaucoup d'insertions à l'avant des ArrayList
objets, donc il y a beaucoup de copie en cours.
Stream<T> input = ... ;
List<T> output =
input.collect(ArrayList::new,
(list, e) -> list.add(0, e),
(list1, list2) -> list1.addAll(0, list2));
Il est probablement possible d'écrire un collecteur inverseur beaucoup plus efficace en utilisant une sorte de structure de données personnalisée.
MISE À JOUR 29/01/2016
Étant donné que cette question a attiré un peu d'attention récemment, je pense que je devrais mettre à jour ma réponse pour résoudre le problème d'insertion au début de ArrayList
. Ce sera horriblement inefficace avec un grand nombre d'éléments, nécessitant une copie O (N ^ 2).
Il est préférable d'utiliser un à la ArrayDeque
place, qui prend en charge efficacement l'insertion à l'avant. Une petite ride est que nous ne pouvons pas utiliser la forme à trois arguments de Stream.collect()
; cela nécessite que le contenu du second argument soit fusionné dans le premier argument, et il n'y a pas d'opération en bloc "ajouter tout à l'avant" Deque
. Au lieu de cela, nous utilisons addAll()
pour ajouter le contenu du premier argument à la fin du second, puis nous renvoyons le second. Cela nécessite l'utilisation de la Collector.of()
méthode d'usine.
Le code complet est le suivant:
Deque<String> output =
input.collect(Collector.of(
ArrayDeque::new,
(deq, t) -> deq.addFirst(t),
(d1, d2) -> { d2.addAll(d1); return d2; }));
Le résultat est un Deque
au lieu d'un List
, mais cela ne devrait pas être un gros problème, car il peut facilement être itéré ou diffusé dans l'ordre maintenant inversé.
IntStream
n'a pas de.sorted(Comparator)
méthode; vous devez passer par unStream<Integer>
premier et inverser là-bas avant de céder unIntStream