Как отсортировать HashSet?


106

Для списков мы используем Collections.sort(List)метод. Что, если мы хотим отсортировать HashSet?


20
A HashSet- неупорядоченная коллекция.
Alexis C.

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

3
Вы можете сначала преобразовать его в список, а затем отсортировать, если вам нужно отсортировать
demongolem

Вы не можете этого сделать, поскольку у a HashSetнет определенного порядка. Ваш вопрос воплощает противоречие в терминах.
Marquis of Lorne

1
используйте TreeSet, и если вы не можете контролировать источник, см. преобразование и использование здесь stackoverflow.com/a/52987487/5153955
Tenflex

Ответы:


114

HashSet не гарантирует какой-либо порядок его элементов. Если вам нужна эта гарантия, подумайте об использовании TreeSet для хранения ваших элементов.

Однако, если вам просто нужно отсортировать элементы для этого одного вхождения, просто временно создайте список и отсортируйте его:

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

...

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

1
Кроме того, если вы используете коллекцию строк, тогдаList<String> sortedList = new ArrayList<String>(yourHashSet);
wisbucky

65

Добавьте все свои объекты в файл TreeSet, вы получите отсортированный Set. Ниже приведен необработанный пример.

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.
Mounika 05

17

Вместо этого вы можете использовать TreeSet .


1
Простое размещение элементов не даст гибкости сортировки в любом порядке с любым элементом внутри него. Вышеупомянутое решение делает.
Джесс

16

Способ сортировки Java 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 это пример того, как естественным образом отсортировать HashSet объекта YourItem по размеру.

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


Не могли бы вы добавить логику для сортировки в определенном порядке?
Джесс

@Jess, я не знаю, какой у вас конкретный порядок, Джесс, вы можете отсортировать его по своему усмотрению с помощью компаратора.
LazerBanana

Я имел в виду, как определить восходящий или нисходящий
Джесс

14

Использовать java.util.TreeSet как фактический объект. Когда вы перебираете эту коллекцию, значения возвращаются в четко определенном порядке.

Если вы используете, java.util.HashSetто порядок зависит от внутренней хэш-функции, которая почти наверняка не является лексикографической (в зависимости от содержимого).


Почему вы предполагаете, что они хранят Stringценности?
Сотириос Делиманолис

Я не думаю, что, возможно, я использую лексографию неточно ;-)
P45 Imminent

3
Это очень неправильно. Он не хранит ключи в лексографическом (sp?) Порядке. Он либо использует их естественный порядок (который зависит от Comparableинтерфейса, который реализуют ключи), либо использует предоставленный Comparator.
Сотириос Делиманолис

Я редактировал. Как думаешь лучше, или надо удалить ответ?
P45 Imminent

1
Если вы переместите HashSetв TreeSet, ваш класс должен реализовать Comparableинтерфейс или предоставить пользовательский Comparator. В противном случае, поскольку вы не можете отсортировать a HashSet, просто преобразуйте его в 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. Создайте новый список и добавьте все элементы, затем отсортируйте его один раз. Если вы хотите сохранить только уникальные элементы (удалите все дубликаты, как это делает set, затем поместите список в 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(...)преобразованного списка), не удосужились спросить OP, какие объекты у вас HashSetесть, т.е. если эти элементы имеют предопределенный естественный порядок или нет, и это не дополнительный вопрос, а обязательный вопрос.

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

Из TreeSetJavaDoc,

Создает новый пустой набор деревьев, отсортированный в соответствии с естественным порядком его элементов. Все элементы, вставленные в набор, должны реализовывать интерфейс Comparable. Кроме того, все такие элементы должны быть взаимно сопоставимы: e1.compareTo (e2) не должен вызывать исключение ClassCastException для любых элементов e1 и e2 в наборе. Если пользователь пытается добавить элемент в набор, который нарушает это ограничение (например, пользователь пытается добавить строковый элемент в набор, элементы которого являются целыми числами), вызов add вызовет исключение ClassCastException.

Вот почему только все ответы на основе потока Java8 - где вы определяете свой компаратор на месте - имеют смысл только потому, что реализация сопоставимого в POJO становится необязательной. Программист определяет компаратор по мере необходимости. Попытка собрать, TreeSetне задав этот фундаментальный вопрос, также неверна (ответ ниндзя). Предполагая , что типы объектов быть Stringили Integerтакже неправильно.

Сказав это, другие проблемы, такие как

  1. Производительность сортировки
  2. Memory Foot Print (сохранение исходного набора и создание новых отсортированных наборов каждый раз, когда выполняется сортировка или вы хотите отсортировать набор на месте и т. Д.)

должны быть и другие соответствующие моменты. Просто указывать на 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);
    }
  }
 }

ввод - вед пракаш шарма яблоко вед банан

Продукция - яблоко банан пракаш шарма вед


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 [эльф, пять, четыре, шесть, два]

Требование для этого метода состоит в том, что объекты набора / списка должны быть сопоставимы (реализовать интерфейс Comparable)


-4

Эта простая команда помогла мне:

myHashSet.toList.sorted

Я использовал это в операторе печати, поэтому, если вам действительно нужно сохранить порядок, вам может потребоваться использовать TreeSets или другие структуры, предложенные в этом потоке.


1
Я не вижу, где у HashSet или Set есть метод toList.
Томас Эйзингер,

1
Для меня это похоже на Scala, который, к сожалению, не решает проблему в Java.
Роберто

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