Come ordinare un HashSet?


106

Per gli elenchi, usiamo il Collections.sort(List)metodo. E se volessimo ordinare un HashSet?


20
A HashSetè una collezione non ordinata.
Alexis C.

2
Non è possibile, dal momento Setche a non ha metodi di accesso casuale (cioè .get()un elemento in un dato indice), che è fondamentalmente richiesto per gli algoritmi di ordinamento;)
fge

3
Potresti prima convertirlo in un elenco, quindi ordinare se è necessario ordinare
demongolem

Non puoi poiché a HashSetnon ha un ordine definito. La tua domanda incarna una contraddizione in termini.
Marchese di Lorne

1
utilizzare un TreeSet e se non è possibile controllare la sorgente di vedere la conversione di un uso qui stackoverflow.com/a/52987487/5153955
Tenflex

Risposte:


114

Un HashSet non garantisce alcun ordine dei suoi elementi. Se hai bisogno di questa garanzia, considera l'utilizzo di un TreeSet per contenere i tuoi elementi.

Tuttavia, se hai solo bisogno dei tuoi elementi ordinati per questa occorrenza, crea solo temporaneamente un elenco e ordina quello:

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

...

List<?> sortedList = new ArrayList<>(yourHashSet);
Collections.sort(sortedList);

1
Inoltre, se stai usando una raccolta di stringhe, alloraList<String> sortedList = new ArrayList<String>(yourHashSet);
wisbucky

65

Aggiungi tutti i tuoi oggetti a TreeSet, otterrai un Set ordinato. Di seguito è riportato un esempio grezzo.

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]

2
Utilizzando TreeSet myTreeSet = new TreeSet(myHashSet);è possibile evitare di aggiungere nuovamente tutti gli elementi a Treeset.
Mounika

17

Puoi invece usare un TreeSet .


1
Il semplice inserimento degli elementi non darà la flessibilità di ordinare su qualsiasi ordine con qualsiasi elemento al suo interno. La soluzione di cui sopra fa.
Jess il

15

Il modo in Java 8 per ordinarlo sarebbe:

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::getSizeè un esempio di come ordinare naturalmente l'HashSet di YourItem in base alle dimensioni.

* Collectors.toList()raccoglierà il risultato dell'ordinamento in una lista con cui dovrai catturarloList<Foo> sortedListOfFoo =


Puoi, per favore, aggiungere la logica per ordinarlo in un ordine specifico?
Jess il

@ Jess non so qual è l'ordine specifico per te Jess, puoi ordinarlo come desideri utilizzando il comparatore.
LazerBanana

Intendevo, come definire l'Ascendente o Discendente
Jess

14

Usa java.util.TreeSetcome oggetto reale. Quando si ripete su questa raccolta, i valori tornano in un ordine ben definito.

Se si utilizza, java.util.HashSetl'ordine dipende da una funzione hash interna che quasi certamente non è lessicografica (basata sul contenuto).


Perché presumi che memorizzino Stringvalori?
Sotirios Delimanolis

Non lo so, forse il mio uso del lessico è impreciso ;-)
P45 Imminente il

3
È molto sbagliato. Non memorizza le chiavi in ​​ordine lessografico (sp?). Utilizza il loro ordinamento naturale (che dipende Comparabledall'interfaccia implementata dai tasti) oppure utilizza il file Comparator.
Sotirios Delimanolis

Ho modificato. Meglio secondo te o dovrei cancellare la risposta?
P45 Imminente il

1
Nel caso in cui sposti un HashSeta TreeSet, la tua classe deve implementare l' Comparableinterfaccia o fornire un file personalizzato Comparator. Altrimenti, poiché non puoi ordinare a HashSet, basta convertirlo in a Liste ordinarlo.
Luiggi Mendoza

5

È possibile utilizzare raccoglitori Java 8 e TreeSet

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


new TreeSet<>(hashSet)è più conciso e probabilmente più efficiente.
devconsole

4

Puoi usare TreeSet come menzionato in altre risposte.

Ecco un po 'più di elaborazione su come 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);

Produzione:

[a1, a2, a3, a4, a5]
a1
a2
b1
b2
b3

4

Gli elementi in HashSet non possono essere ordinati. Ogni volta che metti elementi in HashSet, può rovinare l'ordinamento dell'intero set. È deliberatamente progettato in questo modo per le prestazioni. Quando non ti interessa l'ordine, HashSet sarà il set più efficiente per l'inserimento e la ricerca rapidi.

TreeSet ordinerà automaticamente tutti gli elementi ogni volta che inserisci un elemento.

Forse, quello che stai cercando di fare è ordinare solo una volta. In tal caso, TreeSet non è l'opzione migliore perché deve determinare continuamente il posizionamento degli elementi aggiunti di recente.

La soluzione più efficiente è utilizzare ArrayList. Crea un nuovo elenco e aggiungi tutti gli elementi, quindi ordinalo una volta. Se vuoi conservare solo elementi univoci (rimuovi tutti i duplicati come fa set, quindi metti l'elenco in un LinkedHashSet, manterrà l'ordine che hai già ordinato)

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.

Ora, hai ottenuto un set ordinato se lo desideri in un modulo di elenco, quindi convertilo in elenco.


3

Sulla base della risposta data da @LazerBanana inserirò il mio esempio di un Set ordinato in base all'ID dell'oggetto:

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)

3

Nel caso in cui non vuoi usarne uno, TreeSetpotresti provarlo.

set = set.stream().sorted().collect(Collectors.toCollection(LinkedHashSet::new));

2

A mio modesto parere, la risposta di LazerBanana dovrebbe essere la risposta più votata e accettata perché tutte le altre risposte che puntano a java.util.TreeSet(o prima converti in lista quindi chiama Collections.sort(...)sulla lista convertita) non si sono preoccupate di chiedere a OP come che tipo di oggetti hai, HashSetcioè se quegli elementi hanno o meno un ordinamento naturale predefinito e questa non è una domanda facoltativa ma obbligatoria.

Non puoi entrare e iniziare a inserire i tuoi HashSetelementi in un TreeSettipo di elemento se non implementa già l' Comparableinterfaccia o se non stai esplicitamente passando Comparatoral TreeSetcostruttore.

Da TreeSetJavaDoc,

Costruisce un nuovo insieme di alberi vuoto, ordinato in base all'ordine naturale dei suoi elementi. Tutti gli elementi inseriti nel set devono implementare l'interfaccia Comparable. Inoltre, tutti questi elementi devono essere reciprocamente confrontabili: e1.compareTo (e2) non deve generare ClassCastException per gli elementi e1 ed e2 dell'insieme. Se l'utente tenta di aggiungere un elemento al set che viola questo vincolo (ad esempio, l'utente tenta di aggiungere un elemento stringa a un set i cui elementi sono numeri interi), la chiamata add genererà un'eccezione ClassCastException.

Questo è il motivo per cui solo tutte le risposte basate sul flusso Java8 - in cui definisci il tuo comparatore sul posto - hanno senso solo perché l'implementazione di comparabili in POJO diventa opzionale. Il programmatore definisce il comparatore come e quando necessario. Anche cercare di raccogliere TreeSetsenza porre questa domanda fondamentale è errato (risposta di Ninja). Supponendo che anche i tipi di oggetto siano Stringo non Integersiano corretti.

Detto questo, altre preoccupazioni come,

  1. Ordinamento delle prestazioni
  2. Memory Foot Print (mantenendo il set originale e creando nuovi set ordinati ogni volta che si effettua l'ordinamento o si desidera ordinare il set sul posto, ecc. Ecc.)

dovrebbero essere anche gli altri punti rilevanti. Il solo puntare all'API non dovrebbe essere solo intenzione.

Poiché il set originale contiene già solo elementi univoci e tale vincolo viene mantenuto anche dal set ordinato, quindi il set originale deve essere cancellato dalla memoria poiché i dati vengono duplicati.


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);
    }
  }
 }

input - ved prakash sharma apple ved banana

Risultato - apple banana prakash sharma ved


1

Se vuoi che la fine Collectionsia nella forma di Sete se vuoi definire la tua natural orderinvece di quella di TreeSetallora -

1. Converti HashSetin List
2. Ordinamento personalizzato Listusando Comparator
3. Converti di nuovo Listin LinkedHashSetper mantenere l'ordine
4. Mostra il LinkedHashSet

Programma di esempio -

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);
    }
}

Produzione -

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

Qui la raccolta è stata ordinata come -

Primo - Ordine discendente di Stringlunghezza
Secondo - Ordine discendente della Stringgerarchia alfabetica


0

puoi farlo nei seguenti modi:

Metodo 1:

  1. Crea un elenco e memorizza tutti i valori hashset al suo interno
  2. ordina l'elenco utilizzando Collections.sort ()
  3. Memorizza nuovamente l'elenco in LinkedHashSet poiché conserva l'ordine di inserimento

Metodo 2:

  • Crea un treeSet e memorizza tutti i valori al suo interno.

Il metodo 2 è più preferibile perché l'altro metodo richiede molto tempo per trasferire i dati avanti e indietro tra hashset e list.


0

Non possiamo decidere che gli elementi di un HashSet vengano ordinati automaticamente. Ma possiamo ordinarli convertendoli in TreeSet o qualsiasi elenco come ArrayList o LinkedList ecc.

// 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");

0

Puoi usare la libreria guava per lo stesso

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


0

Puoi avvolgerlo in un TreeSet come questo:

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);   

output:
elementi mySet [1, 3, 4, 5]
elementi treeSet [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);

output:
mySet items [six, four, five, two, elf]
treeSet items [elf, five, four, six, two]

requisito per questo metodo è che gli oggetti dell'insieme / elenco siano confrontabili (implementare l'interfaccia Comparable)


-4

Questo semplice comando ha fatto il trucco per me:

myHashSet.toList.sorted

L'ho usato all'interno di un'istruzione print, quindi se è necessario persistere effettivamente l'ordinamento, potrebbe essere necessario utilizzare TreeSet o altre strutture proposte su questo thread.


1
Non vedo dove HashSet o Set abbia un metodo toList.
Thomas Eizinger

1
A me sembra Scala, che purtroppo non risolve il problema in Java.
Roberto

metodo toList, come è possibile?
Ved Prakash
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.