Jak posortować zestaw HashSet?

106

W przypadku list używamy Collections.sort(List)metody. A co jeśli chcemy posortować HashSet?

Diana
źródło
20
A HashSetto nieuporządkowana kolekcja.
Alexis C.
2
Nie możesz, ponieważ a Setnie ma metod dostępu swobodnego (tj. .get()Elementu o podanym indeksie), co jest w zasadzie wymagane dla algorytmów sortowania;)
fge
3
Możesz najpierw przekonwertować go na listę, a następnie posortować, jeśli chcesz posortować
demongolem
Nie możesz, ponieważ HashSetnie ma zdefiniowanej kolejności. Twoje pytanie uosabia sprzeczność terminów.
Markiz Lorne
1
użyj TreeSet i jeśli nie możesz kontrolować źródła, zobacz konwersję, użycie tutaj stackoverflow.com/a/52987487/5153955
Tenflex

Odpowiedzi:

114

HashSet nie gwarantuje żadnej kolejności swoich elementów. Jeśli potrzebujesz tej gwarancji, rozważ użycie TreeSet do przechowywania elementów.

Jeśli jednak potrzebujesz tylko posortowanych elementów dla tego jednego wystąpienia, po prostu tymczasowo utwórz Listę i posortuj ją:

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

...

List<?> sortedList = new ArrayList<>(yourHashSet);
Collections.sort(sortedList);
isak gilbert
źródło
1
Ponadto, jeśli używasz kolekcji Strings, toList<String> sortedList = new ArrayList<String>(yourHashSet);
wisbucky
65

Dodaj wszystkie swoje obiekty do TreeSet, a otrzymasz posortowany zestaw. Poniżej znajduje się surowy przykład.

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
źródło
2
Używając TreeSet myTreeSet = new TreeSet(myHashSet);możesz uniknąć ponownego dodawania wszystkich elementów do zestawu drzew.
Mounika
17

Zamiast tego możesz użyć TreeSet .

jcarvalho
źródło
1
Samo umieszczenie elementów nie zapewni elastyczności sortowania w dowolnej kolejności z dowolnym elementem w środku. Powyższe rozwiązanie działa.
Jess
16

Sposób sortowania w Javie 8 to:

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::getSizeto przykład, jak naturalnie sortować HashSet YourItem według rozmiaru.

* Collectors.toList()ma zamiar zebrać wynik sortowania do listy, z którą będziesz musiał go przechwycićList<Foo> sortedListOfFoo =

LazerBanana
źródło
Czy możesz dodać logikę, aby posortować to w określonej kolejności?
Jess
@Jess, nie wiem, jaka jest konkretna kolejność dla ciebie, Jess, możesz ją posortować według własnego uznania za pomocą komparatora.
LazerBanana
Chodziło mi o to, jak zdefiniować Rosnąco lub Malejąco
Jess
14

Użyj java.util.TreeSetjako rzeczywistego obiektu. Podczas iteracji po tej kolekcji wartości wracają w dobrze zdefiniowanej kolejności.

Jeśli używasz, java.util.HashSetkolejność zależy od wewnętrznej funkcji skrótu, która prawie na pewno nie jest leksykograficzna (oparta na treści).

P45 Nieuchronne
źródło
Dlaczego zakładasz, że przechowują Stringwartości?
Sotirios Delimanolis
Nie jestem, chociaż może moje użycie leksografii jest nieprecyzyjne ;-)
P45 Imminent
3
To bardzo źle. Nie przechowuje kluczy w porządku leksograficznym (sp?). Używa ich naturalnej kolejności (która zależy od Comparableinterfejsu, który implementują klucze) lub korzysta z dostarczonego Comparator.
Sotirios Delimanolis
Edytowałem. Myślisz, że lepiej, czy powinienem usunąć odpowiedź?
P45 Imminent
1
W przypadku przeniesienia HashSetdo TreeSet, Twoja klasa musi zaimplementować Comparableinterfejs lub zapewnić niestandardowy Comparator. W przeciwnym razie, ponieważ nie możesz posortować a HashSet, po prostu przekonwertuj go na a Listi posortuj.
Luiggi Mendoza
5

Możesz użyć kolektorów Java 8 i TreeSet

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

Ninja
źródło
new TreeSet<>(hashSet)jest bardziej zwięzły i prawdopodobnie bardziej wydajny.
devconsole
4

Możesz użyć TreeSet, jak wspomniano w innych odpowiedziach.

Oto trochę więcej informacji na temat tego, jak z niego korzystać:

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

Wynik:

[a1, a2, a3, a4, a5]
a1
a2
b1
b2
b3
Alisa
źródło
4

Nie można sortować elementów w HashSet. Za każdym razem, gdy umieszczasz elementy w HashSet, może to zepsuć porządek całego zestawu. Jest celowo zaprojektowany w ten sposób z myślą o wydajności. Kiedy nie zależy Ci na kolejności, HashSet będzie najbardziej wydajnym zestawem do szybkiego wstawiania i wyszukiwania.

TreeSet automatycznie posortuje wszystkie elementy za każdym razem, gdy wstawisz element.

Być może to, co próbujesz zrobić, to posortować tylko raz. W takim przypadku TreeSet nie jest najlepszą opcją, ponieważ musi przez cały czas określać położenie nowo dodanych elementów.

Najbardziej wydajnym rozwiązaniem jest użycie ArrayList. Utwórz nową listę i dodaj wszystkie elementy, a następnie posortuj ją raz. Jeśli chcesz zachować tylko unikalne elementy (usuń wszystkie duplikaty, tak jak robi to set, a następnie umieść listę w LinkedHashSet, zachowa kolejność, którą już posortowałeś)

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.

Teraz masz posortowany zestaw, jeśli chcesz go w formie listy, a następnie przekonwertuj go na listę.

off99555
źródło
3

Na podstawie odpowiedzi udzielonej przez @LazerBanana zamieszczę własny przykład Zestawu posortowanego według Id Obiektu:

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
źródło
3

Na wypadek, gdybyś nie chciał tego użyć, TreeSetmożesz spróbować.

set = set.stream().sorted().collect(Collectors.toCollection(LinkedHashSet::new));
Ankit Sharma
źródło
2

Moim skromnym zdaniem odpowiedź LazerBanana powinna być najwyżej ocenioną odpowiedzią i zaakceptowaną, ponieważ wszystkie inne odpowiedzi wskazujące java.util.TreeSet(lub najpierw przekonwertowane na listę, a następnie wywołane Collections.sort(...)na przekonwertowanej liście) nie zadały sobie trudu, aby zapytać OP, jakiego rodzaju obiekty masz HashSet, tj. czy te elementy mają predefiniowany porządek naturalny, czy nie, i nie jest to pytanie opcjonalne, ale pytanie obowiązkowe.

Po prostu nie możesz wejść i zacząć umieszczać swoich HashSetelementów w TreeSettypie elementu if nie implementuje jeszcze Comparableinterfejsu lub jeśli nie przekazujesz jawnie Comparatordo TreeSetkonstruktora.

Z TreeSetJavaDoc,

Konstruuje nowy, pusty zestaw drzew, posortowany zgodnie z naturalnym uporządkowaniem jego elementów. Wszystkie elementy wstawiane do zestawu muszą implementować interfejs Comparable. Ponadto wszystkie takie elementy muszą być wzajemnie porównywalne: e1.compareTo (e2) nie może zgłaszać wyjątku ClassCastException dla żadnych elementów e1 i e2 w zestawie. Jeśli użytkownik spróbuje dodać element do zestawu, który narusza to ograniczenie (na przykład użytkownik próbuje dodać element ciągu do zestawu, którego elementy są liczbami całkowitymi), wywołanie add zwróci ClassCastException.

Dlatego tylko wszystkie odpowiedzi oparte na strumieniu Java8 - gdzie definiujesz swój komparator na miejscu - mają sens tylko dlatego, że implementacja porównywalnego w POJO staje się opcjonalna. Programista definiuje komparator w razie potrzeby. Próba zebrania się TreeSetbez zadawania tego podstawowego pytania jest również niepoprawna (odpowiedź Ninja). Zakładanie, że typy obiektów są Stringlub Integerteż są nieprawidłowe.

To powiedziawszy, inne obawy, takie jak:

  1. Wydajność sortowania
  2. Memory Foot Print (zachowywanie oryginalnego zestawu i tworzenie nowych posortowanych zestawów za każdym razem, gdy sortowanie jest wykonywane lub chcesz posortować zestaw na miejscu itp.)

powinny być również inne istotne punkty. Samo wskazanie na API nie powinno być tylko intencją.

Ponieważ oryginalny zestaw zawiera już tylko unikalne elementy i to ograniczenie jest również utrzymywane przez posortowany zestaw, więc oryginalny zestaw musi zostać usunięty z pamięci, ponieważ dane są zduplikowane.

Sabir Khan
źródło
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);
    }
  }
 }

wejście - ved prakash sharma apple ved banana

Wyjście - jabłko bananowe prakash sharma ved

Ved Prakash
źródło
1

Jeśli chcesz, aby koniec Collectionbył w formie Seti jeśli chcesz zdefiniować swój własny, natural ordera nie ten TreeSet-

1. Przekształć HashSetw List
2. Własny posortuj Listużywając Comparator
3. Zamień z powrotem Listna, LinkedHashSetaby zachować porządek
4. Wyświetl LinkedHashSet

Przykładowy program -

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

Wynik -

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

Tutaj zbiór został posortowany jako -

Pierwszy - Malejąca kolejność Stringdługości
Druga - Malejąca kolejność w Stringhierarchii alfabetycznej

Payel Senapati
źródło
0

możesz to zrobić w następujący sposób:

Metoda 1:

  1. Utwórz listę i zapisz w niej wszystkie wartości skrótu
  2. posortuj listę za pomocą Collections.sort ()
  3. Przechowuj listę z powrotem w LinkedHashSet, ponieważ zachowuje kolejność reklamową

Metoda 2:

  • Utwórz drzewo Ustaw i zapisz w nim wszystkie wartości.

Metoda 2 jest bardziej preferowana, ponieważ druga metoda zajmuje dużo czasu na przesyłanie danych tam iz powrotem między hashset a listą.

Sujit
źródło
0

Nie możemy zdecydować, że elementy HashSet będą sortowane automatycznie. Ale możemy je sortować, konwertując na TreeSet lub dowolną listę, taką jak ArrayList lub LinkedList itp.

// 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
źródło
0

Możesz użyć biblioteki guawy do tego samego

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
źródło
0

Możesz zawinąć go w TreeSet w następujący sposób:

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

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

wyjście:
elementy mySet [sześć, cztery, pięć, dwa, elf]
treeSet elementy [elf, pięć, cztery, sześć, dwa]

wymaganiem dla tej metody jest, aby obiekty zestawu / listy były porównywalne (zaimplementuj interfejs Comparable)

prędkość
źródło
-4

Ta prosta komenda załatwiła sprawę:

myHashSet.toList.sorted

Użyłem tego w instrukcji print, więc jeśli chcesz rzeczywiście zachować porządkowanie, może być konieczne użycie TreeSets lub innych struktur proponowanych w tym wątku.

Glenn Strycker
źródło
1
Nie widzę, gdzie HashSet lub Set ma metodę toList.
Thomas Eizinger
1
Dla mnie wygląda to jak Scala, która niestety nie rozwiązuje problemu w Javie.
Roberto
toList, jak to możliwe?
Ved Prakash,