【问题标题】:How to sort a HashSet?如何对 HashSet 进行排序?
【发布时间】:2014-04-18 22:31:33
【问题描述】:

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

【问题讨论】:

  • A HashSet 是一个无序集合。
  • 你不能,因为Set 没有随机访问方法(即.get() 给定索引处的元素),这基本上是排序算法所必需的;)
  • 如果需要排序,可以先将其转换为列表,然后再排序
  • 你不能因为 HashSet 没有定义的顺序。您的问题在术语上体现了矛盾。
  • 使用 TreeSet,如果您无法控制源代码,请在此处查看转换用法stackoverflow.com/a/52987487/5153955

标签: java sorting collections set hashset


【解决方案1】:

如果您希望结尾 Collection 采用 Set 的形式,并且如果您想定义自己的 natural order 而不是 TreeSet,那么 -

  1. HashSet 转换为List
  2. 使用Comparator自定义排序List
  3. List 转换回LinkedHashSet 以维持秩序
  4. 显示LinkedHashSet

    示例程序 -
package demo31;

import java.util.*;
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 字母层次结构的降序

【讨论】:

    【解决方案2】:

    HashSet 转换为List,然后使用Collection.sort() 对其进行排序

    List<String> list = new ArrayList<String>(hset);
    Collections.sort(List)
    

    【讨论】:

      【解决方案3】:

      将所有对象添加到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]
      

      更新

      您还可以使用TreeSet 的构造函数,该构造函数将HashSet 作为参数。

      HashSet myHashSet = new HashSet();
      myHashSet.add(1);
      myHashSet.add(23);
      myHashSet.add(45);
      myHashSet.add(12);
      
      TreeSet myTreeSet = new TreeSet(myHashSet);
      System.out.println(myTreeSet); // Prints [1, 12, 23, 45]
      

      感谢 @mounika 的更新。

      【讨论】:

      • 使用TreeSet myTreeSet = new TreeSet(myHashSet);可以避免再次将所有元素添加到Treeset。
      • 这将删除重复项,因为 OP 要求对 HashSet 进行排序,并且它可能包含重复值。
      • 哈希集可能包含重复值!!真的!??
      【解决方案4】:

      以下是我的示例代码,它已经通过指向 cmets 中的代码来回答,我仍在分享,因为它包含完整的代码

      package Collections;
      
      import java.util.*;
      
      public class TestSet {
      
          public static void main(String[] args) {
      
              Set<String> objset = new HashSet<>();
      
              objset.add("test");
              objset.add("abc");
              objset.add("abc");
              objset.add("mas");
              objset.add("vas");
      
              Iterator itset = objset.iterator();
              while(itset.hasNext())
              {
                  System.out.println(itset.next());
              }
      
              TreeSet<String> treeobj = new TreeSet(objset);
              System.out.println(treeobj);
      
      
          }
      }
      

      TreeSet treeobj = new TreeSet(objset);这里我们调用树集构造函数,它将调用 addAll 方法来添加对象。

      请参阅下面的 TreeSet 类中的代码,

      public TreeSet(Collection<? extends E> c) {
              this();
              addAll(c);
          }
      

      【讨论】:

        【解决方案5】:

        HashSet 中的元素无法排序。每当您将元素放入 HashSet 时,它都会打乱整个集合的顺序。它是为了性能而故意设计的。当你不关心顺序时,HashSet 将是频繁插入和查询最有效的集合。

        TreeSet 是您可以使用的替代方案。当您迭代树集时,您将自动获得排序的元素。 但它会调整树以尝试在每次插入元素时保持排序。

        也许,您要做的只是排序一次。在这种情况下,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
        

        现在,如果您希望它以列表形式出现,那么您已经获得了一个排序集,然后将其转换为列表。

        【讨论】:

        • 您的说法“每次插入元素时,TreeSet 都会自动对所有元素进行排序”是不正确的。如果您更改用于比较列表中对象的值,然后添加一个新对象,它将被放置,就好像您更改的对象具有其原始值一样。因此,假设没有任何元素更改其用于对列表进行排序的值,则只有新项目被放置在正确的位置。
        • @Jaco-BenVosloo 谢谢。我已经编辑了答案以反映您的评论。
        【解决方案6】:

        如果您不想使用 TreeSet,您可以尝试使用 java 流来获得简洁的代码。

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

        【讨论】:

          【解决方案7】:

          根据@LazerBanana 给出的答案,我将举出我自己的按对象 ID 排序的 Set 示例:

          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)
          

          【讨论】:

            【解决方案8】:

            您可以像这样将它包装在 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 接口)

            【讨论】:

              【解决方案9】:

              【讨论】:

                【解决方案10】:

                使用java.util.TreeSet 作为实际对象。当您遍历此集合时,这些值会以明确定义的顺序返回。

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

                【讨论】:

                • 你为什么假设他们存储 String 值?
                • 我不是,虽然也许我对 lexographic 的使用不精确 ;-)
                • 大错特错。它不按 lexographic (sp?) 顺序存储键。它要么使用它们的自然顺序(这取决于键实现的Comparable 接口),要么使用提供的Comparator
                • 我已经编辑过了。你觉得更好,还是我应该删除答案?
                • 如果您将HashSet 移动到TreeSet,您的类必须实现Comparable 接口或提供自定义Comparator。否则,由于您无法对HashSet 进行排序,因此只需将其转换为List 并对其进行排序。
                【解决方案11】:

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

                但是,如果您只需要针对这一事件对元素进行排序,则只需临时创建一个 List 并对其进行排序:

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

                【讨论】:

                • 另外,如果你使用的是字符串集合,那么List&lt;String&gt; sortedList = new ArrayList&lt;String&gt;(yourHashSet);
                【解决方案12】:

                以我的拙见,LazerBanana 的答案应该是评分最高的答案并被接受,因为所有其他指向 java.util.TreeSet 的答案(或先转换为列表,然后在转换后的列表中调用 Collections.sort(...))都懒得问OP 作为您的HashSet 具有什么样的对象,即这些元素是否具有预定义的自然顺序,这不是可选问题,而是强制性问题。

                如果元素类型还没有实现Comparable 接口或者如果你没有明确地将Comparator 传递给TreeSet 构造函数,你就不能进入并开始将你的HashSet 元素放入TreeSet .

                来自TreeSetJavaDoc,

                构造一个新的空树集,按照自然排序 其元素的排序。插入集合的所有元素必须 实现 Comparable 接口。此外,所有这些元素 必须相互比较:e1.compareTo(e2) 不能抛出 集合中任何元素 e1 和 e2 的 ClassCastException。如果用户 尝试向集合中添加违反此约束的元素 (例如,用户试图将一个字符串元素添加到一个集合中,其 元素是整数),添加调用将抛出 ClassCastException。

                这就是为什么只有所有基于 Java8 流的答案(您在现场定义比较器的地方)才有意义,因为在 POJO 中实现可比较变得可选。程序员在需要时定义比较器。试图收集到TreeSet 而不问这个基本问题也是不正确的(忍者的回答)。假设对象类型为StringInteger 也是不正确的。

                话虽如此,其他问题如,

                1. 分拣性能
                2. 内存足迹(保留原始集并在每次排序完成时创建新的排序集或希望对集进行就地排序等)

                也应该是其他相关点。仅仅指向 API 不应该只是意图。

                由于原始集已仅包含 唯一 元素,并且该约束也由排序集维护,因此由于数据重复,因此需要从内存中清除原始集。

                【讨论】:

                  【解决方案13】:

                  您可以使用 Java 8 收集器和 TreeSet

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

                  【讨论】:

                  • new TreeSet&lt;&gt;(hashSet) 更简洁,可能更高效。
                  【解决方案14】:

                  你也可以使用 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
                      }
                  });
                  

                  【讨论】:

                    【解决方案15】:

                    我们不能决定 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");
                    

                    【讨论】:

                      【解决方案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是一个例子,如何按大小对YourItem的HashSet进行自然排序。

                      *Collectors.toList() 将收集排序结果到列表中,您需要使用List&lt;Foo&gt; sortedListOfFoo = 捕获它

                      【讨论】:

                      • 能否请您添加逻辑以按特定顺序对其进行排序?
                      • @Jess 我不知道 Jess 的具体顺序是什么,你可以使用比较器随意排序。
                      • 我的意思是,如何定义升序或降序
                      【解决方案17】:
                      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

                      【讨论】:

                        【解决方案18】:

                        您可以使用其他答案中提到的 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
                        

                        【讨论】:

                          【解决方案19】:

                          您可以改用TreeSet

                          【讨论】:

                          • 仅仅放置元素不会提供任何排序​​的灵活性,其中包含任何元素。上面的解决方案可以。
                          【解决方案20】:

                          您可以通过以下方式做到这一点:

                          方法一:

                          1. 创建一个列表并将所有哈希集值存储到其中
                          2. 使用 Collections.sort() 对列表进行排序
                          3. 将列表存储回 LinkedHashSet,因为它保留了插入顺序

                          方法二:

                          • 创建一个 treeSet 并将所有值存储到其中。

                          方法 2 更可取,因为另一种方法在 hashset 和 list 之间来回传输数据会消耗大量时间。

                          【讨论】:

                            【解决方案21】:

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

                            myHashSet.toList.sorted
                            

                            我在打印语句中使用了它,所以如果您需要实际保持排序,您可能需要使用 TreeSets 或此线程上建议的其他结构。

                            【讨论】:

                            • 我看不到 HashSet 或 Set 哪里有方法 toList
                            • 这在我看来就像 Scala,不幸的是它并不能解决 Java 中的问题。
                            • toList 方法,怎么可能?
                            猜你喜欢
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 2015-09-06
                            • 1970-01-01
                            • 2018-11-20
                            • 2014-06-02
                            • 1970-01-01
                            相关资源
                            最近更新 更多