Як сортувати HashSet?


106

Для списків ми використовуємо Collections.sort(List)метод. Що робити, якщо ми хочемо сортувати HashSet?


20
A HashSet- це не упорядкована колекція.
Олексій С.

2
Ви не можете, оскільки у a Setнемає методів випадкового доступу (тобто .get()елемента в заданому індексі), який в основному необхідний для алгоритмів сортування;)
fge

3
Ви можете спершу перетворити його у список, а потім сортувати, якщо вам потрібно буде сортувати
demongolem

Ви не можете, оскільки у вас HashSetнемає визначеного порядку. Ваше запитання втілює протиріччя в термінах.
Маркіз Лорн

1
використовувати TreeSet і якщо ви не можете управляти джерелом бачити конверсію в використання тут stackoverflow.com/a/52987487/5153955
Tenflex

Відповіді:


114

HashSet не гарантує жодного порядку своїх елементів. Якщо вам потрібна ця гарантія, розгляньте можливість використання TreeSet для утримання елементів.

Однак якщо вам просто потрібні ваші елементи, відсортовані за цим явищем, просто тимчасово створіть список і сортуйте таке:

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

...

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

1
Крім того, якщо ви використовуєте колекцію Strings, тоList<String> sortedList = new ArrayList<String>(yourHashSet);
wisbucky

65

Додайте всі свої об'єкти до TreeSet, ви отримаєте відсортований набір. Нижче наведено необроблений приклад.

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
Використовуючи TreeSet myTreeSet = new TreeSet(myHashSet);ви можете уникнути додавання всіх елементів до Treeset знову.
Муніка

17

Ви можете використовувати TreeSet замість цього.


1
Просто розміщення елементів не дає гнучкості сортування в будь-якому порядку з будь-яким елементом всередині нього. Наведене вище рішення робить.
Джесс

16

Якість 8 способом сортування це було б:

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це приклад того, як сортувати хеш-набір YourItem за природним розміром.

* Collectors.toList()збирає результат сортування до Списку, з яким вам знадобиться захопити йогоList<Foo> sortedListOfFoo =


Ви можете, будь ласка, додати логіку, щоб сортувати її у визначеному порядку?
Джесс

@Jess Я не знаю, який конкретний порядок для вас Джесс, ви можете сортувати його за бажанням, використовуючи компаратор.
LazerBanana

Я мав на увазі, як визначити
Джесс

14

Використовувати java.util.TreeSetяк власне об’єкт. Коли ви повторюєте цю колекцію, значення повертаються у чітко визначеному порядку.

Якщо ви використовуєте, java.util.HashSetто порядок залежить від внутрішньої хеш-функції, яка майже точно не є лексикографічною (на основі вмісту).


Чому ви припускаєте, що вони зберігають Stringзначення?
Сотіріос Деліманоліс

Я не хоч, можливо, моє використання лексографічного неточне ;-)
P45 Неминуче

3
Це дуже неправильно. Він не зберігає ключі в лексографічному (sp?) Порядку. Він або використовує їх природне впорядкування (що залежить від Comparableінтерфейсу, який ключі реалізують), або використовує наданий Comparator.
Сотіріос Деліманоліс

Я відредагував. Ви вважаєте, що краще, чи я повинен видалити відповідь?
P45 Неминучий

1
У випадку, якщо ви переходите HashSetна TreeSet, ваш клас повинен реалізувати Comparableінтерфейс або надати користувальницький Comparator. В іншому випадку, оскільки ви не можете сортувати a HashSet, просто перетворіть його в a Listі відсортуйте.
Луїджі Мендоса

5

Можна використовувати колектори Java 8 та TreeSet

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


new TreeSet<>(hashSet)є більш стислим і, ймовірно, більш ефективним.
devconsole

4

Ви можете використовувати TreeSet, як зазначено в інших відповідях.

Ось трохи докладніше про те, як ним користуватися:

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

Вихід:

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

4

Елементи в HashSet не можна сортувати. Щоразу, коли ви вводите елементи в HashSet, це може зіпсувати впорядкування всього набору. Це свідомо розроблено так для виконання. Коли ви не дбаєте про замовлення, HashSet стане найефективнішим набором для швидкого вставки та пошуку.

TreeSet буде сортувати всі елементи автоматично щоразу, коли ви вставляєте елемент.

Можливо, те, що ти намагаєшся, це сортувати лише один раз. У цьому випадку TreeSet - не найкращий варіант, оскільки йому потрібно постійно визначати розміщення щойно доданих елементів.

Найефективнішим рішенням є використання ArrayList. Створіть новий список і додайте всі елементи, після чого сортуйте їх один раз. Якщо ви хочете зберегти лише унікальні елементи (видаліть усі дублікати, як це встановлено, а потім помістіть список у LinkedHashSet, він збереже порядок, який ви вже відсортували)

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.

Тепер ви отримали відсортований набір, якщо ви хочете його у формі списку, а потім перетворите його у список.


3

На основі відповіді, наданої @LazerBanana, я наведу власний приклад набору, відсортованого за ідентифікатором об’єкта:

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

На всякий випадок, якщо ви не хочете використовувати, TreeSetви можете спробувати це.

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

2

На мою скромну думку, відповідь LazerBanana повинна бути найвищою оцінкою і прийнятою, оскільки всі інші відповіді, які вказують на java.util.TreeSet(або спочатку переходять у список, а потім дзвонять Collections.sort(...)у перетворений список), не намагалися запитати ОП, які саме об'єкти у вас HashSetє, тобто якщо ці елементи мають заздалегідь визначене природне впорядкування, чи ні & це не є питанням необов'язковим, а обов'язковим.

Ви просто не можете увійти та почати вводити HashSetелементи у формат TreeSetif, якщо тип елемента ще не реалізує Comparableінтерфейс або якщо ви явно не переходите Comparatorдо TreeSetконструктора.

Від TreeSetJavaDoc,

Побудує новий, порожній набір дерев, відсортований за природним упорядкуванням його елементів. Усі елементи, вставлені в набір, повинні реалізовувати інтерфейс Порівняння. Крім того, всі такі елементи повинні бути взаємно порівнянні: e1.compareTo (e2) не повинен викидати ClassCastException для будь-яких елементів e1 та e2 у наборі. Якщо користувач намагається додати елемент до набору, який порушує це обмеження (наприклад, користувач намагається додати рядковий елемент до набору, елементи якого є цілими числами), виклик add викине ClassCastException.

Тому лише всі відповіді на основі потоку Java8 - де ви визначаєте компаратор на місці - мають сенс лише тому, що реалізація порівнянного в POJO стає необов'язковою. Програміст визначає компаратор як і коли це потрібно. Спроба зібратися, TreeSetне задаючи цього фундаментального питання, також неправильна (відповідь Ніндзя). Припустимо, що типи об'єктів є Stringабо Integerтакож є невірними.

Сказавши це, інші проблеми, такі як,

  1. Сортування продуктивності
  2. Друк на нозі пам’яті (зберігання оригінального набору та створення нових відсортованих наборів щоразу, коли сортування проводиться чи бажаєте сортувати набір за місцем тощо тощо)

повинні бути і інші відповідні моменти. Просто вказівка ​​на API не повинна бути лише наміром.

Оскільки оригінальний набір вже містить лише унікальні елементи, а обмеження також підтримується відсортованим набором, тому оригінальний набір потрібно очистити з пам'яті, оскільки дані дублюються.


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

вхід - ved prakash sharma apple ved банан

Вихід - яблучний банан пракаш шарма


1

Якщо ви хочете , хочете кінець , Collectionщоб бути у формі , Setі якщо ви хочете , щоб визначити свій власний , natural orderа ніж TreeSetдалі -

1. Перетворити HashSetв List
2. Настроюваний Сортування з Listдопомогою Comparator
3. Перетворити назад Listв LinkedHashSetпідтримання порядку
4. Покажіть LinkedHashSet

Зразок програми -

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

Вихід -

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

Тут колекцію відсортовано як -

Перше - Порядок зменшення Stringдовжини
Другий - Порядок спадання Stringалфавітної ієрархії


0

це можна зробити наступними способами:

Спосіб 1:

  1. Створіть список і збережіть у ньому всі значення хештету
  2. сортувати список за допомогою Collections.sort ()
  3. Зберігайте список назад у LinkedHashSet, оскільки він зберігає порядок вставки

Спосіб 2:

  • Створіть treeSet і збережіть у ньому всі значення.

Спосіб 2 є більш кращим, оскільки інший метод вимагає багато часу для передачі даних вперед і назад між хештетом і списком.


0

Ми не можемо вирішити, що елементи HashSet будуть сортуватися автоматично. Але ми можемо їх сортувати, перетворившись у TreeSet або будь-який список типу ArrayList або LinkedList тощо.

// 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

Ви можете використовувати бібліотеку guava для того ж

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

Ви можете загорнути його в TreeSet так:

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

вихід:
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);

вихід:
mySet items [шість, чотири, п’ять, два, ельфи]
treeSet items [ельф, п’ять, чотири, шість, два]

Вимога цього методу полягає в тому, що об'єкти набору / списку повинні бути порівнянними (реалізувати Порівняльний інтерфейс)


-4

Ця проста команда зробила для мене хитрість:

myHashSet.toList.sorted

Я використовував це в операторі друку, тому, якщо вам потрібно буде продовжувати замовлення, можливо, вам доведеться використовувати TreeSets або інші структури, запропоновані на цій темі.


1
Я не бачу, де в HashSet або Set є метод toList.
Томас Ейзінгер

1
Мені це схоже на Scala, який, на жаль, не вирішує проблеми на Java.
Роберто

toList метод, як це можливо?
Вед Пракаш
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.