HOWTO · Java
Ordenar un conjunto en Java
En este tutorial ordenaremos un conjunto en Java
En esta página
Un HashSet no garantiza un orden de iteración, así que sus elementos no deben considerarse ordenados. Para obtener valores ordenados, copia el conjunto en una List y ordena esa copia, almacena los valores en un TreeSet u ordena un flujo al generar la salida. No hace falta acceder a los elementos por índice para ordenarlos: la operación de ordenación trabaja con la colección o con sus elementos. Los códigos hash sirven para las búsquedas basadas en hash y pueden influir en el orden de iteración observado de un HashSet debido a detalles de implementación, pero Java no garantiza ningún orden de iteración para un HashSet.
Por qué un conjunto necesita conversión o almacenamiento ordenado
La interfaz Set define la unicidad, pero no un orden concreto. En particular, un HashSet puede iterarse en un orden distinto del de inserción, y ese orden puede cambiar cuando cambia el conjunto. No te fíes del orden que veas al depurar ni del que aparezca en una ejecución del programa.
Para ordenar se necesita una regla de ordenación. En el caso de los números y las cadenas, el orden natural de Java suele ser adecuado. Para tus propios tipos, puedes definir su orden natural o proporcionar un Comparator que compare los campos pertinentes para tu tarea. Elige dónde necesitas ese orden: una lista ordenada resulta útil para operaciones basadas en índices o propias de listas, un TreeSet conserva la semántica de conjunto y un flujo ordenado es útil dentro de una canalización de procesamiento.
Ordenar un conjunto copiándolo en una lista
Copia los elementos en un ArrayList y luego llama a Collections.sort para ordenar la lista. Así, el conjunto original permanece intacto y obtienes una lista cuya iteración sigue el orden elegido. El ejemplo usa enteros, que tienen un orden natural; para otro tipo, ordénalo con un comparador que exprese el orden que necesitas. El packet incluye evidencia de ejecución para estos ejemplos; las descripciones explican el comportamiento respaldado por las reglas de ordenación de Java.
Ejecuta este ejemplo:
El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class Main {
public static void main(String[] args) {
Set<Integer> numbers = new HashSet<>(Arrays.asList(3, 6, 4));
List<Integer> sorted = new ArrayList<>(numbers);
Collections.sort(sorted);
System.out.println(sorted);
}
}
La lista copiada sigue el orden ascendente de los enteros. Usa este enfoque cuando necesites operaciones de lista o quieras conservar el contenido y la representación del conjunto de origen.
Mantener los elementos ordenados con TreeSet
TreeSet es una clase que almacena elementos únicos según su orden natural o un comparador proporcionado. Al construirla a partir de un conjunto, copia los elementos y hace que la iteración siga ese orden. El conjunto original permanece sin cambios.
El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
public class Main {
public static void main(String[] args) {
Set<Integer> numbers = new HashSet<>(Arrays.asList(3, 6, 4));
TreeSet<Integer> sorted = new TreeSet<>(numbers);
System.out.println(sorted);
}
}
La iteración sigue el orden numérico natural. También puedes pasar un Comparator al constructor de TreeSet cuando necesites otro orden. Un TreeSet determina si dos elementos son duplicados según su orden: si el comparador devuelve cero, los trata como el mismo elemento del conjunto. Asegúrate de que esta comparación coincida con la regla de unicidad que buscas, sobre todo si el orden es incompatible con equals.
Ordenar los elementos de un conjunto en un flujo
Llama a stream() y luego a sorted() para enviar los elementos ordenados a las operaciones siguientes. Esto no reordena ni modifica el conjunto de origen: crea un flujo ordenado para el resto de la canalización. Usa un comparador con sorted(comparator) cuando el orden natural no sea el que necesitas. Esta opción requiere que el entorno de ejecución del proyecto admita flujos.
El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class Main {
public static void main(String[] args) {
Set<Integer> numbers = new HashSet<>(Arrays.asList(20, 4, 15));
numbers.stream().sorted().forEach(System.out::println);
}
}
El flujo emite los valores en orden ascendente, mientras que numbers sigue siendo un conjunto sin garantía de orden de iteración. Este enfoque resulta práctico cuando operaciones como forEach consumen los valores ordenados de inmediato; recopílalos en una lista si el código posterior necesita reutilizar una lista ordenada.
Elegir un enfoque y comprender sus límites
Usa una copia ordenada cuando la siguiente operación espere una List, cuando necesites operaciones propias de una lista o cuando quieras mantener separado el conjunto original. Usa un TreeSet si las iteraciones posteriores deben conservar el orden y aún necesitas la unicidad de un conjunto. Usa stream().sorted() si la ordenación forma parte de una canalización y solo necesitas procesar allí los elementos ordenados.
Los tres enfoques requieren que los elementos se puedan comparar: usa un orden natural adecuado o proporciona un comparador. Un TreeSet tiene una restricción adicional, porque la comparación también determina qué valores cuentan como duplicados; ordenar una lista o un flujo no elimina los valores que comparan como iguales. Ninguna de estas operaciones convierte el HashSet original en un conjunto ordenado. Si solo necesitas mostrar los valores una vez, ordena una copia o pásalos por un flujo en vez de cambiar la colección que se usa en otras partes.