Pregunta general: ¿Cuál es la forma correcta de revertir una secuencia? Suponiendo que no sabemos en qué tipo de elementos consta ese flujo, ¿cuál es la forma genérica de revertir cualquier flujo?
Pregunta especifica:
IntStream
proporciona un método de rango para generar números enteros en un rango específico IntStream.range(-range, 0)
, ahora que quiero revertirlo, cambiar el rango de 0 a negativo no funcionará, tampoco puedo usarInteger::compare
List<Integer> list = Arrays.asList(1,2,3,4);
list.stream().sorted(Integer::compare).forEach(System.out::println);
con IntStream
voy a obtener este error del compilador
Error: (191, 0) ajc: el método
sorted()
en el tipoIntStream
no es aplicable para los argumentos (Integer::compare
)
¿que me estoy perdiendo aqui?
IntStream
no tiene.sorted(Comparator)
método; tienes que pasar por unStream<Integer>
primero y revertir allí antes de ceder unIntStream
IntStream.range(0, n)
orden inverso, haga algo comomap(i -> n - i - 1)
. No es necesario hacer boxeo y clasificación.1, 3, 2
, ¿cuál es el resultado esperado? ¿Desea la transmisión inversa como2, 3, 1
o la transmisión ordenada como3, 2, 1
?Respuestas:
Para la pregunta específica de generar un reverso
IntStream
, intente algo como esto: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.
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.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 deStream.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, usamosaddAll()
para agregar el contenido del primer argumento al final del segundo, y luego devolvemos el segundo. Esto requiere el uso delCollector.of()
método de fábrica.El código completo es este:
El resultado es un en
Deque
lugar de unList
, pero eso no debería ser un gran problema, ya que se puede iterar o transmitir fácilmente en el orden ahora invertido.fuente
IntStream.iterate(to-1, i->i-1).limit(to-from)
.limit(endExcl-(long)startIncl)
en su lugar, pero para transmisiones tan grandes, de todos modos, se desaconseja mucho ya que es mucho menos eficiente que larange
solución basada. Cuando escribí el comentario, no sabía la diferencia de eficiencia.Solución elegante
fuente
Comparable
...Muchas de las soluciones aquí clasifican o invierten
IntStream
, pero eso requiere innecesariamente un almacenamiento intermedio. La solución de Stuart Marks es el camino a seguir:También maneja correctamente el desbordamiento, pasando esta prueba:
fuente
Estreams
nombre (voy a eliminarlo de la publicación). Es una de las clases de utilidad interna de nuestra empresa, que utilizamos para complementarjava.util.stream.Stream
losstatic
métodos.StreamEx
especificando el paso:IntStreamEx.rangeClosed(from-1, to, -1)
Pregunta general:
Stream no almacena ningún elemento.
Por lo tanto, no es posible iterar elementos en el orden inverso sin almacenar los elementos en alguna colección intermedia.
Actualización: Cambió LinkedList a ArrayDeque (mejor) ver aquí para más detalles
Huellas dactilares:
Por cierto, el uso del
sort
método no es correcto, ya que ordena, NO se invierte (suponiendo que la secuencia puede tener elementos desordenados)Pregunta especifica:
Me encontré con este sencillo, fácil e intuitiva (@Holger copiado comentario )
fuente
sorted
ydistinct
realmente almacenan un resultado intermedio. Consulte los documentos de la API del paquete para obtener información al respecto.No storage
en la misma página. Incluso almacena, no podemos acceder a ese almacenamiento (así queNo storage
está bien, supongo)sin lib externo ...
fuente
Si se aplica
Comparable<T>
(por ej.Integer
,String
,Date
), Puede hacerlo utilizandoComparator.reverseOrder()
.fuente
Stream.of(1,3,2)
el resultado,Stream.of(3,2,1)
NO seríaStream.of(2,3,1)
Puede definir su propio recopilador que recopila los elementos en orden inverso:
Y úsalo como:
Utilizo una ArrayList en orden de avance para insertar eficientemente los elementos de recopilación (al final de la lista) y Guava Lists.verse para dar una vista inversa de la lista sin hacer otra copia.
Estos son algunos casos de prueba para el recopilador personalizado:
fuente
StreamUtils de cyclops- react tiene un método de flujo inverso ( javadoc ).
Funciona al recopilar en una ArrayList y luego hacer uso de la clase ListIterator que puede iterar en cualquier dirección, para iterar hacia atrás sobre la lista.
Si ya tiene una Lista, será más eficiente
fuente
Sugeriría usar jOOλ , es una gran biblioteca que agrega muchas funcionalidades útiles a las secuencias y lambdas de Java 8.
Luego puede hacer lo siguiente:
Simple como eso. Es una biblioteca bastante ligera y vale la pena agregarla a cualquier proyecto Java 8.
fuente
Aquí está la solución que se me ocurrió:
luego usando esos comparadores:
fuente
Collections.reverseOrder()
existe desde Java 1.2 y funciona conInteger
...¿Qué tal este método de utilidad?
Parece funcionar con todos los casos sin duplicación.
fuente
fuente
La forma más simple (recolección simple: admite flujos paralelos):
Forma avanzada (admite secuencias paralelas de forma continua):
Tenga en cuenta que puede extenderse rápidamente a otro tipo de secuencias (IntStream, ...).
Pruebas:
Resultados:
Notas adicionales: No
simplest way
es tan útil cuando se usa con otras operaciones de flujo (la combinación de recopilación rompe el paralelismo). Eladvance way
no tiene ese problema, y también mantiene las características iniciales de la transmisión, por ejemploSORTED
, y así, es la forma de usarlo con otras operaciones de transmisión después de lo contrario.fuente
Se podría escribir un recopilador que recopile elementos en orden inverso:
Y úsalo así:
Respuesta original (contiene un error, no funciona correctamente para flujos paralelos):
Un método inverso de flujo de propósito general podría verse así:
fuente
No solo Java8, pero si usa el método Lists.reverse () de guava en conjunto, puede lograr esto fácilmente:
fuente
Con respecto a la cuestión específica de generar un reverso
IntStream
:a partir de Java 9 , puede usar la versión de tres argumentos de
IntStream.iterate(...)
:dónde:
IntStream.iterate(int seed, IntPredicate hasNext, IntUnaryOperator next);
seed
- el elemento inicial;hasNext
- un predicado para aplicar a los elementos para determinar cuándo debe terminar la secuencia;next
- una función que se aplicará al elemento anterior para producir un nuevo elemento.fuente
Como referencia, estaba viendo el mismo problema, quería unir el valor de cadena de los elementos de flujo en el orden inverso.
itemList = {last, middle, first} => first, middle, last
Comencé a usar una colección intermedia
collectingAndThen
de comonad o elArrayDeque
coleccionista de Stuart Marks , aunque no estaba contento con la colección intermedia y la transmisión de nuevoAsí que repetí la respuesta de Stuart Marks que estaba usando la
Collector.of
fábrica, que tiene el interesante acabado lambda.Dado que en este caso la secuencia no es paralela, el combinador no es tan relevante, lo uso de
insert
todos modos en aras de la coherencia del código, pero no importa, ya que dependería de qué constructor de cadenas se construya primero.Miré el StringJoiner, sin embargo, no tiene un
insert
método.fuente
Respondiendo la pregunta específica de revertir con IntStream, a continuación funcionó para mí:
fuente
ArrayDeque
son más rápidos en la pila que un Stack o LinkedList. "push ()" inserta elementos en la parte frontal del Dequefuente
Cadena de inversión o cualquier matriz
la división se puede modificar según el delimitador o el espacio
fuente
la solución más simple es usar
List::listIterator
yStream::generate
fuente
Stream.generate()
genera en flujo infinito, por lo que la llamada alimit()
es muy importante aquí.Así es como lo hago.
No me gusta la idea de crear una nueva colección y revertirla.
La idea del mapa IntStream # es bastante clara, pero prefiero el método iterativo IntStream #, porque creo que la idea de una cuenta regresiva a cero se expresa mejor con el método iterativo y es más fácil de entender en términos de caminar la matriz de atrás hacia adelante.
Aquí hay algunas pruebas para demostrar que funciona:
fuente
En todo esto no veo la respuesta a la que iría primero.
Esta no es exactamente una respuesta directa a la pregunta, pero es una posible solución al problema.
Simplemente construya la lista al revés en primer lugar. Si puede, use una LinkedList en lugar de una ArrayList y cuando agregue elementos use "Push" en lugar de agregar. La lista se construirá en el orden inverso y luego se transmitirá correctamente sin ninguna manipulación.
Esto no se ajusta a los casos en los que se trata de matrices o listas primitivas que ya se utilizan de varias maneras, pero que funcionan bien en un sorprendente número de casos.
fuente
Este método funciona con cualquier Stream y es compatible con Java 8:
fuente
La forma más genérica y más fácil de revertir una lista será:
fuente
Comparator
. Como resultado, nadie puede garantizarle que este "truco" funcionará en cualquier versión futura de Java con cualquier algoritmo de clasificación. El mismo truco no funciona para el flujo paralelo, por ejemplo, ya que el algoritmo de ordenamiento paralelo se usaComparator
de manera diferente. Para la ordenación secuencial, funciona por pura casualidad. No recomendaría a nadie que use esta solución.System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");
public static <T> void reverseHelper(List<T> li){ li.parallelStream() .sorted((x,y)->-1) .collect(Collectors.toList()) .forEach(System.out::println); }
reverseHelper(IntStream.range(0, 8193).boxed().collect(Collectors.toList()))
(el resultado puede depender de la cantidad de núcleos).Java 8 forma de hacer esto:
fuente