Para la pregunta específica de generar un reverso IntStream
, intente algo como esto:
static IntStream revRange(int from, int to) {
return IntStream.range(from, to)
.map(i -> to - i + from - 1);
}
Esto evita el boxeo y la clasificación.
Para la pregunta general de cómo revertir un flujo de cualquier tipo, no sé si hay una forma "adecuada". Hay un par de maneras en las que puedo pensar. Ambos terminan almacenando los elementos de la secuencia. No sé cómo revertir una secuencia sin almacenar los elementos.
Esta primera forma almacena los elementos en una matriz y los lee en una secuencia en orden inverso. Tenga en cuenta que, dado que no conocemos el tipo de tiempo de ejecución de los elementos de transmisión, no podemos escribir la matriz correctamente, lo que requiere una conversión no verificada.
@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]);
}
Otra técnica utiliza coleccionistas para acumular los elementos en una lista inversa. Esto hace muchas inserciones en la parte frontal de los ArrayList
objetos, por lo que hay muchas copias en curso.
Stream<T> input = ... ;
List<T> output =
input.collect(ArrayList::new,
(list, e) -> list.add(0, e),
(list1, list2) -> list1.addAll(0, list2));
Probablemente sea posible escribir un recopilador de inversión mucho más eficiente utilizando algún tipo de estructura de datos personalizada.
ACTUALIZACIÓN 2016-01-29
Dado que esta pregunta ha recibido un poco de atención recientemente, creo que debería actualizar mi respuesta para resolver el problema de inserción al frente ArrayList
. Esto será terriblemente ineficiente con una gran cantidad de elementos, que requieren copia de O (N ^ 2).
Es preferible usar un ArrayDeque
lugar, que admite de manera eficiente la inserción en la parte delantera. Una pequeña arruga es que no podemos usar la forma de tres argumentos de Stream.collect()
; requiere que el contenido del segundo argumento se fusione con el primer argumento, y no hay una operación masiva "agregar todo al frente" Deque
. En su lugar, usamos addAll()
para agregar el contenido del primer argumento al final del segundo, y luego devolvemos el segundo. Esto requiere el uso del Collector.of()
método de fábrica.
El código completo es este:
Deque<String> output =
input.collect(Collector.of(
ArrayDeque::new,
(deq, t) -> deq.addFirst(t),
(d1, d2) -> { d2.addAll(d1); return d2; }));
El resultado es un en Deque
lugar de un List
, pero eso no debería ser un gran problema, ya que se puede iterar o transmitir fácilmente en el orden ahora invertido.
IntStream
no tiene.sorted(Comparator)
método; tienes que pasar por unStream<Integer>
primero y revertir allí antes de ceder unIntStream