Comment trier un HashSet?

106

Pour les listes, nous utilisons la Collections.sort(List)méthode. Et si nous voulons trier un HashSet?

Diane
la source
20
A HashSetest une collection non ordonnée.
Alexis C.
2
Vous ne pouvez pas, car a Setn'a pas de méthodes d'accès aléatoire (c'est-à-dire .get()un élément à un index donné), ce qui est fondamentalement requis pour les algorithmes de tri;)
fge
3
Vous pouvez d'abord le convertir en liste, puis trier si vous avez besoin de trier
demongolem
Vous ne pouvez pas car a HashSetn'a pas d'ordre défini. Votre question incarne une contradiction dans les termes.
Marquis of Lorne
1
utilisez un TreeSet et si vous ne pouvez pas contrôler la source, voyez la conversion, une utilisation ici stackoverflow.com/a/52987487/5153955
Tenflex

Réponses:

114

Un HashSet ne garantit aucun ordre de ses éléments. Si vous avez besoin de cette garantie, pensez à utiliser un TreeSet pour contenir vos éléments.

Cependant, si vous avez juste besoin que vos éléments soient triés pour cette occurrence, créez simplement temporairement une liste et triez-la:

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

...

List<?> sortedList = new ArrayList<>(yourHashSet);
Collections.sort(sortedList);
isak gilbert
la source
1
De plus, si vous utilisez une collection de chaînes, alorsList<String> sortedList = new ArrayList<String>(yourHashSet);
wisbucky
65

Ajoutez tous vos objets au TreeSet, vous obtiendrez un ensemble trié. Voici un exemple brut.

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
la source
2
En utilisant, TreeSet myTreeSet = new TreeSet(myHashSet);vous pouvez éviter d'ajouter à nouveau tous les éléments à Treeset.
Mounika
17

Vous pouvez utiliser un TreeSet à la place.

jcarvalho
la source
1
Le simple fait de mettre les éléments ne donnera pas la flexibilité de trier sur n'importe quel ordre avec n'importe quel élément à l'intérieur. La solution ci-dessus le fait.
Jess
16

Java 8 pour le trier serait:

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::getSizec'est un exemple comment trier naturellement le HashSet de YourItem par taille.

* Collectors.toList()va collecter le résultat du tri dans une liste avec laquelle vous devrez le capturerList<Foo> sortedListOfFoo =

LazerBanana
la source
Pouvez-vous s'il vous plaît, ajouter la logique pour le trier dans un ordre spécifique?
Jess
@Jess je ne sais pas quelle est la commande spécifique pour vous Jess, vous pouvez la trier comme vous le souhaitez en utilisant le comparateur.
LazerBanana
Je voulais dire, comment définir l'ascendant ou le décroissant
Jess
14

Utilisez java.util.TreeSetcomme objet réel. Lorsque vous parcourez cette collection, les valeurs reviennent dans un ordre bien défini.

Si vous utilisez, java.util.HashSetl'ordre dépend d'une fonction de hachage interne qui n'est certainement pas lexicographique (basée sur le contenu).

P45 imminent
la source
Pourquoi supposez-vous qu'ils stockent des Stringvaleurs?
Sotirios Delimanolis
Je ne suis pas bien que peut-être que mon utilisation du lexographique soit imprécise ;-)
P45 Imminent
3
C'est vraiment faux. Il ne stocke pas les clés dans l'ordre lexographique (sp?). Il utilise soit leur ordre naturel (qui dépend de l' Comparableinterface implémentée par les clés), soit le fichier fourni Comparator.
Sotirios Delimanolis
J'ai édité. Vous pensez mieux, ou devrais-je supprimer la réponse?
P45 Imminent
1
Dans le cas où vous déplacez un HashSetvers TreeSet, votre classe doit implémenter une Comparableinterface ou fournir un fichier personnalisé Comparator. Sinon, puisque vous ne pouvez pas trier a HashSet, convertissez-le simplement en a Listet triez-le.
Luiggi Mendoza
5

Vous pouvez utiliser les collecteurs Java 8 et TreeSet

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

Ninja
la source
new TreeSet<>(hashSet)est plus concis et probablement plus efficace.
devconsole
4

Vous pouvez utiliser TreeSet comme mentionné dans d'autres réponses.

Voici un peu plus de détails sur la façon de l'utiliser:

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

Production:

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

Les éléments de HashSet ne peuvent pas être triés. Chaque fois que vous mettez des éléments dans HashSet, cela peut perturber l'ordre de l'ensemble. Il est délibérément conçu comme ça pour la performance. Lorsque vous ne vous souciez pas de la commande, HashSet sera l'ensemble le plus efficace pour une insertion et une recherche rapides.

TreeSet triera automatiquement tous les éléments à chaque fois que vous insérez un élément.

Peut-être que vous essayez de trier une seule fois. Dans ce cas, TreeSet n'est pas la meilleure option car il doit déterminer le placement des éléments nouvellement ajoutés à tout moment.

La solution la plus efficace consiste à utiliser ArrayList. Créez une nouvelle liste et ajoutez tous les éléments puis triez-la une fois. Si vous souhaitez ne conserver que des éléments uniques (supprimez tous les doublons comme le fait set, puis mettez la liste dans un LinkedHashSet, il conservera l'ordre que vous avez déjà trié)

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.

Maintenant, vous avez obtenu un ensemble trié si vous le voulez sous forme de liste, puis convertissez-le en liste.

off99555
la source
3

Sur la base de la réponse donnée par @LazerBanana, je vais mettre mon propre exemple d'ensemble trié par l'ID de l'objet:

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
la source
3

Au cas où vous ne voudriez pas en utiliser, TreeSetvous pouvez essayer ceci.

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

À mon humble avis, la réponse de LazerBanana devrait être la réponse la mieux notée et acceptée car toutes les autres réponses pointant vers java.util.TreeSet(ou d'abord converties en liste puis appelées Collections.sort(...)sur la liste convertie) n'ont pas pris la peine de demander à OP quel type d'objets vous avez, HashSetc'est-à-dire si ces éléments ont un ordre naturel prédéfini ou non et ce n'est pas une question facultative mais une question obligatoire.

Vous ne pouvez tout simplement pas entrer et commencer à mettre vos HashSetéléments dans un TreeSettype d'élément if n'implémente pas déjà l' Comparableinterface ou si vous ne passez pas explicitement Comparatorau TreeSetconstructeur.

Depuis TreeSetJavaDoc,

Construit un nouvel ensemble d'arbres vide, trié selon l'ordre naturel de ses éléments. Tous les éléments insérés dans l'ensemble doivent implémenter l'interface Comparable. De plus, tous ces éléments doivent être comparables entre eux: e1.compareTo (e2) ne doit pas lancer d'exception ClassCastException pour les éléments e1 et e2 de l'ensemble. Si l'utilisateur tente d'ajouter un élément à l'ensemble qui viole cette contrainte (par exemple, l'utilisateur tente d'ajouter un élément de chaîne à un ensemble dont les éléments sont des entiers), l'appel d'ajout lèvera une ClassCastException.

C'est pourquoi seules toutes les réponses basées sur le flux Java8 - où vous définissez votre comparateur sur place - n'ont de sens que car la mise en œuvre de comparables dans POJO devient facultative. Le programmeur définit le comparateur au fur et à mesure des besoins. Essayer de se rassembler TreeSetsans poser cette question fondamentale est également incorrect (réponse de Ninja). En supposant que les types d'objets sont Stringou Integersont également incorrects.

Cela dit, d'autres préoccupations comme,

  1. Performances de tri
  2. Empreinte mémoire (en conservant l'ensemble d'origine et en créant de nouveaux ensembles triés à chaque fois que le tri est effectué ou que vous souhaitez trier l'ensemble sur place, etc.)

devraient également être les autres points pertinents. Le simple fait de pointer vers l'API ne devrait pas être uniquement une intention.

Puisque l'ensemble d'origine ne contient déjà que des éléments uniques et que cette contrainte est également maintenue par ensemble trié, l'ensemble d'origine doit être effacé de la mémoire car les données sont dupliquées.

Sabir Khan
la source
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);
    }
  }
 }

Entrée - ved prakash sharma apple ved banana

Sortie - pomme banane prakash sharma ved

Ved Prakash
la source
1

Si vous voulez que la fin Collectionsoit sous la forme de Setet si vous voulez définir la vôtre natural orderplutôt que celle de TreeSetalors -

1. Convertissez le HashSeten List
2. Tri personnalisé en Listutilisant Comparator
3. Reconvertissez le Listen LinkedHashSetpour maintenir l'ordre
4. Affichez le LinkedHashSet

Exemple de programme -

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

Production -

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

Ici, la collection a été triée comme -

Première - Ordre décroissant de Stringlongueur
Seconde - Ordre décroissant de la Stringhiérarchie alphabétique

Payel Senapati
la source
0

vous pouvez le faire des manières suivantes:

Méthode 1:

  1. Créez une liste et stockez-y toutes les valeurs de hachage
  2. trier la liste à l'aide de Collections.sort ()
  3. Stockez la liste dans LinkedHashSet car il préserve l'ordre d'insertion

Méthode 2:

  • Créez un treeSet et stockez-y toutes les valeurs.

La méthode 2 est plus préférable car l'autre méthode prend beaucoup de temps pour transférer des données dans les deux sens entre le hachage et la liste.

Sujit
la source
0

On ne peut pas décider que les éléments d'un HashSet seraient triés automatiquement. Mais nous pouvons les trier en les convertissant en TreeSet ou en n'importe quelle liste comme ArrayList ou 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
la source
0

Vous pouvez utiliser la bibliothèque de goyave pour le même

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
la source
0

Vous pouvez l'envelopper dans un TreeSet comme ceci:

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

sortie:
éléments mySet [1, 3, 4, 5]
éléments 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);

sortie:
éléments mySet [six, quatre, cinq, deux, elf]
éléments treeSet [elf, cinq, quatre, six, deux]

La condition requise pour cette méthode est que les objets de l'ensemble / de la liste doivent être comparables (implémenter l'interface Comparable)

rapidité
la source
-4

Cette simple commande a fait l'affaire pour moi:

myHashSet.toList.sorted

J'ai utilisé ceci dans une instruction d'impression, donc si vous devez réellement persister la commande, vous devrez peut-être utiliser TreeSets ou d'autres structures proposées sur ce fil.

Glenn Strycker
la source
1
Je ne vois pas où HashSet ou Set a une méthode toList.
Thomas Eizinger
1
Cela me ressemble à Scala, ce qui ne résout malheureusement pas le problème en Java.
Roberto
méthode toList, comment est-ce possible?
Ved Prakash