¿Cómo ordenar un HashSet?

106

Para las listas, usamos el Collections.sort(List)método. ¿Y si queremos ordenar un HashSet?

Diana
fuente
20
A HashSetes una colección desordenada.
Alexis C.
2
No puede, ya Setque no tiene métodos de acceso aleatorio (es decir, .get()un elemento en un índice dado), que es básicamente necesario para los algoritmos de ordenación;)
fge
3
Primero puede convertirlo en una lista y luego ordenar si necesita ordenar
demongolem
No puede porque HashSetno tiene un orden definido. Tu pregunta encierra una contradicción de términos.
Marqués de Lorne
1
use un TreeSet y si no puede controlar la fuente, vea la conversión y el uso aquí stackoverflow.com/a/52987487/5153955
Tenflex

Respuestas:

114

Un HashSet no garantiza ningún orden de sus elementos. Si necesita esta garantía, considere usar un TreeSet para contener sus elementos.

Sin embargo, si solo necesita que sus elementos estén ordenados para esta única ocurrencia, simplemente cree temporalmente una Lista y ordene eso:

Set<?> yourHashSet = new HashSet<>();

...

List<?> sortedList = new ArrayList<>(yourHashSet);
Collections.sort(sortedList);
isak gilbert
fuente
1
Además, si está utilizando una colección de cadenas, entoncesList<String> sortedList = new ArrayList<String>(yourHashSet);
wisbucky
65

Agregue todos sus objetos al TreeSet, obtendrá un Conjunto ordenado. A continuación se muestra un ejemplo en bruto.

HashSet myHashSet = new HashSet();
myHashSet.add(1);
myHashSet.add(23);
myHashSet.add(45);
myHashSet.add(12);

TreeSet myTreeSet = new TreeSet();
myTreeSet.addAll(myHashSet);
System.out.println(myTreeSet); // Prints [1, 12, 23, 45]
Abdullah Khan
fuente
2
Al usarlo TreeSet myTreeSet = new TreeSet(myHashSet);, puede evitar agregar todos los elementos a Treeset nuevamente.
Mounika
17

En su lugar, puede utilizar un TreeSet .

jcarvalho
fuente
1
El simple hecho de colocar los elementos no dará la flexibilidad de clasificar en cualquier orden con cualquier elemento dentro. La solución anterior lo hace.
Jess
15

Java 8 forma de ordenarlo sería:

fooHashSet.stream()
  .sorted(Comparator.comparing(Foo::getSize)) //comparator - how you want to sort it
  .collect(Collectors.toList()); //collector - what you want to collect it to

* Foo::getSizees un ejemplo de cómo ordenar el HashSet de YourItem de forma natural por tamaño.

* Collectors.toList()va a recopilar el resultado de la clasificación en una Lista con la que deberá capturarloList<Foo> sortedListOfFoo =

LazerBanana
fuente
¿Puedes agregar la lógica para ordenarlo en un orden específico?
Jess
@Jess, no sé cuál es el orden específico para ti Jess, puedes ordenarlo como quieras usando el comparador.
LazerBanana
Quiero decir, cómo definir el ascendente o descendente
Jess
14

Úselo java.util.TreeSetcomo el objeto real. Cuando itera sobre esta colección, los valores vuelven en un orden bien definido.

Si lo usa java.util.HashSet, el orden depende de una función hash interna que casi con certeza no es lexicográfica (basada en el contenido).

P45 inminente
fuente
¿Por qué asume que almacenan Stringvalores?
Sotirios Delimanolis
No lo creo, aunque tal vez mi uso de lexográfico sea impreciso ;-)
P45 Inminente
3
Está muy mal. No almacena claves en orden lexográfico (¿sp?). O usa su orden natural (que depende de la Comparableinterfaz que implementan las claves) o usa el proporcionado Comparator.
Sotirios Delimanolis
He editado ¿Crees mejor, o debería eliminar la respuesta?
P45 inminente
1
En caso de que mueva un HashSeta TreeSet, su clase debe implementar una Comparableinterfaz o proporcionar un archivo Comparator. De lo contrario, dado que no puede ordenar a HashSet, simplemente conviértalo en a Listy ordénelo.
Luiggi Mendoza
5

Puede utilizar los recopiladores de Java 8 y TreeSet

list.stream().collect(Collectors.toCollection(TreeSet::new))

Ninja
fuente
new TreeSet<>(hashSet)es más conciso y probablemente más eficiente.
devconsole
4

Puede usar TreeSet como se menciona en otras respuestas.

Aquí hay un poco más de elaboración sobre cómo usarlo:

TreeSet<String> ts = new TreeSet<String>();
ts.add("b1");
ts.add("b3");
ts.add("b2");
ts.add("a1");
ts.add("a2");
System.out.println(ts);
for (String s: ts)
    System.out.println(s);

Salida:

[a1, a2, a3, a4, a5]
a1
a2
b1
b2
b3
Alisa
fuente
4

Los elementos de HashSet no se pueden ordenar. Siempre que coloque elementos en HashSet, puede estropear el orden de todo el conjunto. Está diseñado deliberadamente así para el rendimiento. Cuando no le importa el orden, HashSet será el conjunto más eficiente para una rápida inserción y búsqueda.

TreeSet ordenará todos los elementos automáticamente cada vez que inserte un elemento.

Quizás, lo que está tratando de hacer es ordenar solo una vez. En ese caso, TreeSet no es la mejor opción porque necesita determinar la ubicación de los elementos recién agregados todo el tiempo.

La solución más eficaz es utilizar ArrayList. Cree una nueva lista y agregue todos los elementos y luego ordénela una vez. Si desea retener solo elementos únicos (elimine todos los duplicados como lo hace el conjunto, luego coloque la lista en un LinkedHashSet, mantendrá el orden que ya ha ordenado)

List<Integer> list = new ArrayList<>();
list.add(6);
list.add(4);
list.add(4);
list.add(5);
Collections.sort(list);
Set<Integer> unique = new LinkedHashSet<>(list); // 4 5 6
// The above line is not copying the objects! It only copies references.

Ahora, ha obtenido un conjunto ordenado si lo desea en forma de lista y luego conviértalo en lista.

off99555
fuente
3

En base a la respuesta dada por @LazerBanana, pondré mi propio ejemplo de un conjunto ordenado por la identificación del objeto:

Set<Clazz> yourSet = [...];

yourSet.stream().sorted(new Comparator<Clazz>() {
    @Override
    public int compare(Clazz o1, Clazz o2) {
        return o1.getId().compareTo(o2.getId());
    }
}).collect(Collectors.toList()); // Returns the sorted List (using toSet() wont work)
Leandro S
fuente
3

En caso de que no quieras usar un, TreeSetpuedes probar esto.

set = set.stream().sorted().collect(Collectors.toCollection(LinkedHashSet::new));
Ankit Sharma
fuente
2

En mi humilde opinión, la respuesta de LazerBanana debería ser la respuesta mejor calificada y aceptada porque todas las demás respuestas que apuntan a java.util.TreeSet(o primero convertir a la lista y luego llamar Collections.sort(...)a la lista convertida) no se molestaron en preguntar OP como qué tipo de objetos HashSettiene, es decir. si esos elementos tienen un orden natural predefinido o no, y esa no es una pregunta opcional sino obligatoria.

Simplemente no puede entrar y comenzar a poner sus HashSetelementos en un TreeSetsi el tipo de elemento aún no implementa la Comparableinterfaz o si no está pasando explícitamente Comparatoral TreeSetconstructor.

Desde TreeSetJavaDoc,

Construye un nuevo conjunto de árboles vacío, ordenado según el orden natural de sus elementos. Todos los elementos insertados en el conjunto deben implementar la interfaz Comparable. Además, todos estos elementos deben ser mutuamente comparables: e1.compareTo (e2) no debe lanzar una ClassCastException para ningún elemento e1 y e2 en el conjunto. Si el usuario intenta agregar un elemento al conjunto que viola esta restricción (por ejemplo, el usuario intenta agregar un elemento de cadena a un conjunto cuyos elementos son números enteros), la llamada a agregar arrojará una ClassCastException.

Es por eso que solo todas las respuestas basadas en secuencias de Java8, donde define su comparador en el lugar, solo tienen sentido porque la implementación de comparable en POJO se vuelve opcional. El programador define el comparador como y cuando sea necesario. Tratar de recopilar TreeSetsin hacer esta pregunta fundamental también es incorrecto (respuesta de Ninja). Asumir que los tipos de objeto son Stringo Integertambién es incorrecto.

Habiendo dicho eso, otras preocupaciones como,

  1. Rendimiento de clasificación
  2. Pie de memoria (conserva el juego original y crea nuevos juegos ordenados cada vez que se realiza la clasificación o desea clasificar el juego en su lugar, etc., etc.)

también deberían ser los otros puntos relevantes. Apuntar a la API no debería ser solo una intención.

Dado que el conjunto original ya contiene solo elementos únicos y esa restricción también se mantiene mediante el conjunto ordenado, el conjunto original debe borrarse de la memoria ya que los datos están duplicados.

Sabir Khan
fuente
1
1. Add all set element in list -> al.addAll(s);
2. Sort all the elements in list using -> Collections.sort(al);


 public class SortSetProblem {
 public static void main(String[] args) {
    ArrayList<String> al = new ArrayList();
    Set<String> s = new HashSet<>();
    s.add("ved");
    s.add("prakash");
    s.add("sharma");
    s.add("apple");
    s.add("ved");
    s.add("banana");
    System.out.println("Before Sorting");
    for (String s1 : s) {
        System.out.print("  " + s1);
    }

    System.out.println("After Sorting");
    al.addAll(s);
    Collections.sort(al);
    for (String set : al) {
        System.out.print(" " + set);
    }
  }
 }

entrada - ved prakash sharma apple ved banana

Salida - manzana banana prakash sharma ved

Ved Prakash
fuente
1

Si desea que el final Collectiontenga la forma de Sety si desea definir el suyo en natural orderlugar del de TreeSetentonces:

1. Convierta el HashSeten List
2. Ordene el Listuso personalizado Comparator
3. Convierta de nuevo el Listen LinkedHashSetpara mantener el orden
4. Visualice el LinkedHashSet

Programa de muestra -

package demo31;

import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

public class App26 {
    public static void main(String[] args) {
        Set<String> set = new HashSet<>();
        addElements(set);
        List<String> list = new LinkedList<>();
        list = convertToList(set);
        Collections.sort(list, new Comparator<String>() {
            @Override
            public int compare(String s1, String s2) {
                int flag = s2.length() - s1.length();
                if(flag != 0) {
                    return flag;
                } else {
                    return -s1.compareTo(s2);
                }
            }
        });
        Set<String> set2 = new LinkedHashSet<>();
        set2 = convertToSet(list);
        displayElements(set2);
    }
    public static void addElements(Set<String> set) {
        set.add("Hippopotamus");
        set.add("Rhinocerous");
        set.add("Zebra");
        set.add("Tiger");
        set.add("Giraffe");
        set.add("Cheetah");
        set.add("Wolf");
        set.add("Fox");
        set.add("Dog");
        set.add("Cat");
    }
    public static List<String> convertToList(Set<String> set) {
        List<String> list = new LinkedList<>();
        for(String element: set) {
            list.add(element);
        }
        return list;
    }
    public static Set<String> convertToSet(List<String> list) {
        Set<String> set = new LinkedHashSet<>();
        for(String element: list) {
            set.add(element);
        }
        return set;
    }
    public static void displayElements(Set<String> set) {
        System.out.println(set);
    }
}

Salida -

[Hippopotamus, Rhinocerous, Giraffe, Cheetah, Zebra, Tiger, Wolf, Fox, Dog, Cat]

Aquí la colección se ha ordenado como -

Primero - Orden descendente de Stringlongitud
Segundo - Orden descendente de Stringjerarquía alfabética

Payel Senapati
fuente
0

puede hacer esto de las siguientes formas:

Método 1:

  1. Cree una lista y almacene todos los valores de hashset en ella
  2. ordenar la lista usando Collections.sort ()
  3. Almacene la lista nuevamente en LinkedHashSet ya que conserva el orden de inserción

Método 2:

  • Cree un treeSet y almacene todos los valores en él.

El método 2 es más preferible porque el otro método consume mucho tiempo para transferir datos entre el conjunto de hash y la lista.

Sujit
fuente
0

No podemos decidir que los elementos de un HashSet se ordenarán automáticamente. Pero podemos ordenarlos convirtiéndolos en TreeSet o cualquier List como ArrayList o LinkedList, etc.

// Create a TreeSet object of class E
TreeSet<E> ts = new TreeSet<E> ();

// Convert your HashSet into TreeSet
ts.addAll(yourHashSet);

System.out.println(ts.toString() + "\t Sorted Automatically");
alexvipul
fuente
0

Puede usar la biblioteca de guayaba para el mismo

Set<String> sortedSet = FluentIterable.from(myHashSet).toSortedSet(new Comparator<String>() {
    @Override
    public int compare(String s1, String s2) {
        // descending order of relevance
        //required code
    }
});
Ankita Bhowmik
fuente
0

Puede envolverlo en un TreeSet como este:

Set mySet = new HashSet();
mySet.add(4);
mySet.add(5);
mySet.add(3);
mySet.add(1);
System.out.println("mySet items "+ mySet);   

TreeSet treeSet = new TreeSet(mySet);   
System.out.println("treeSet items "+ treeSet);   

salida:
mySet items [1, 3, 4, 5]
treeSet items [1, 3, 4, 5]

Set mySet = new HashSet();
mySet.add("five");
mySet.add("elf");
mySet.add("four");
mySet.add("six");
mySet.add("two");
System.out.println("mySet items "+ mySet);

TreeSet treeSet = new TreeSet(mySet);
System.out.println("treeSet items "+ treeSet);

salida:
elementos de mySet [seis, cuatro, cinco, dos, elfo]
elementos del conjunto de árboles [elf, cinco, cuatro, seis, dos]

El requisito para este método es que los objetos del conjunto / lista deben ser comparables (implementar la interfaz Comparable)

velocidad
fuente
-4

Este simple comando hizo el truco para mí:

myHashSet.toList.sorted

Usé esto dentro de una declaración de impresión, por lo que si realmente necesita persistir en el pedido, es posible que deba usar TreeSets u otras estructuras propuestas en este hilo.

Glenn Strycker
fuente
1
No veo dónde HashSet o Set tienen un método toList.
Thomas Eizinger
1
Eso me parece Scala, que desafortunadamente no resuelve el problema en Java.
Roberto
método toList, ¿cómo es posible?
Ved Prakash