如何对HashSet进行排序?


106

对于列表,我们使用Collections.sort(List)方法。如果我们要排序HashSet怎么办?


20
A HashSet是无序集合。
Alexis C.

2
您不能这样做,因为a Set没有随机访问方法(即,.get()给定索引中的元素),这基本上是排序算法所必需的;)
fge 2014年

3
您可以先将其转换为列表,然后再进行排序(如果需要排序)
demongolem 2014年

因为a HashSet没有定义的顺序,所以不能。您的问题体现了术语上的矛盾。
罗恩侯爵,

1
使用TreeSet,如果您无法控制源,请在此处查看转换的用法 stackoverflow.com/a/52987487/5153955
Tenflex

Answers:


114

HashSet不能保证其元素的任何顺序。如果需要此保证,请考虑使用TreeSet来保存元素。

但是,如果只需要为这种情况对元素排序,则只需临时创建一个List并对其进行排序:

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 '19

17

您可以改用TreeSet


1
仅仅放置元素不会给在其中包含任何元素的任何顺序进行排序的灵活性。以上解决方案可以。
杰西

15

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这是一个示例,说明如何按大小对YourItem的HashSet进行自然排序。

* Collectors.toList()将收集排序到列表中的结果,您将需要使用它来捕获它List<Foo> sortedListOfFoo =


能否请您添加逻辑以按特定顺序对其进行排序?
Jess

@杰西我不知道杰西的具体命令是什么,您可以使用比较器根据需要对其进行排序。
LazerBanana

我的意思是,如何定义升序或降序
Jess

14

使用java.util.TreeSet作为实际的对象。遍历此集合时,值将以定义良好的顺序返回。

如果使用,java.util.HashSet则顺序取决于内部哈希函数,该函数几乎可以肯定不是字典式的(基于内容)。


您为什么要假设它们存储String值?
Sotirios Delimanolis 2014年

我并不是说我对词典的使用并不精确;-)
P45即将

3
错了 它不按字典顺序(sp?)存储键。它要么使用它们的自然顺序(取决于Comparable键实现的接口),要么使用提供的Comparator
Sotirios Delimanolis 2014年

我已编辑。您认为更好,还是应该删除答案?
P45即将

1
如果你移动HashSetTreeSet,你的类必须实现Comparable接口或提供自定义Comparator。否则,由于您无法对进行排序HashSet,只需将其转换为List并对其进行排序。
Luiggi Mendoza 2014年

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给出的答案,我将放置一个自己的示例集,该集按对象的ID排序:

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)


2

在我的拙见中,LazerBanana的答案应该是评分最高的答案并被接受,因为所有其他指向java.util.TreeSet(或首先转换为列表,然后Collections.sort(...)在转换后的列表上调用)的答案都没有费心地问OP是您HashSet拥有哪种对象,即如果这些元素具有预定义的自然顺序,则该&不是可选问题,而是强制性问题。

如果元素类型尚未实现接口,或者如果您未显式传递给构造函数,则无法进入并开始将HashSet元素放入。 TreeSetComparableComparatorTreeSet

TreeSetJavaDoc中,

构造一个新的空树集,并根据其元素的自然顺序对其进行排序。插入到集合中的所有元素必须实现Comparable接口。此外,所有这些元素必须相互可比较:e1.compareTo(e2)不得为集合中的任何元素e1和e2引发ClassCastException。如果用户尝试向违反此约束的集合中添加元素(例如,用户尝试向其元素为整数的集合中添加字符串元素),则add调用将引发ClassCastException。

这就是为什么只有所有基于Java8流的答案(您在那儿定义比较器)才有意义的原因,因为在POJO中实现可比性成为可选的。程序员在需要时定义比较器。尝试TreeSet不提出这个基本问题就收集信息也是不正确的(忍者的答案)。假设对象类型为StringInteger也不正确。

话虽如此,其他问题,例如,

  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苹果ved香蕉

输出-苹果香蕉Prakash Sharma Ved


1

如果你旺旺年底Collection将在形式Set,如果你想定义自己的natural order,而不是说的TreeSet那么-

1转换HashSetList
2自定义排序List使用Comparator
3转换回ListLinkedHashSet维持秩序
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

您可以使用番石榴库

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项目[1、3、4、5]
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);

输出:
mySet项目[六,四,五,二,小精灵]
treeSet项目[elf,五,四,六,二]

此方法的要求是集合/列表的对象应该是可比较的(实现Comparable接口)


-4

这个简单的命令对我有用:

myHashSet.toList.sorted

我在print语句中使用了此方法,因此,如果您需要实际保持顺序,则可能需要使用TreeSet或在此线程上建议的其他结构。


1
我看不到HashSet或Set在哪里有方法toList
Thomas Eizinger 2015年

1
在我看来,这就像Scala一样,不幸的是它无法解决Java中的问题。
罗伯托

toList方法,怎么可能?
Ved Prakash'2
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.