Làm thế nào để sắp xếp một HashSet?


106

Đối với danh sách, chúng tôi sử dụng Collections.sort(List)phương pháp. Điều gì xảy ra nếu chúng ta muốn sắp xếp một HashSet?


20
A HashSetlà một tập hợp không có thứ tự.
Alexis C.

2
Bạn có thể không, vì một Setkhông có phương pháp truy cập ngẫu nhiên (ví dụ, .get()một yếu tố tại một chỉ số nhất định), mà về cơ bản cần thiết cho các thuật toán loại;)
FGE

3
Bạn có thể chuyển đổi nó vào một danh sách đầu tiên sau đó sắp xếp nếu bạn cần phải loại
demongolem

Bạn không thể vì a HashSetkhông có một thứ tự xác định. Câu hỏi của bạn thể hiện một sự mâu thuẫn về mặt điều khoản.
Marquis of Lorne

1
sử dụng TreeSet và nếu bạn không thể kiểm soát nguồn, hãy xem chuyển đổi một cách sử dụng tại đây stackoverflow.com/a/52987487/5153955
Tenflex 17/02/19

Câu trả lời:


114

HashSet không đảm bảo bất kỳ thứ tự nào của các phần tử của nó. Nếu bạn cần sự đảm bảo này, hãy cân nhắc sử dụng TreeSet để giữ các phần tử của bạn.

Tuy nhiên, nếu bạn chỉ cần sắp xếp các phần tử của mình cho một lần xuất hiện này, thì chỉ cần tạm thời tạo một Danh sách và sắp xếp:

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

...

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

1
Ngoài ra, nếu bạn đang sử dụng một bộ sưu tập Chuỗi, thìList<String> sortedList = new ArrayList<String>(yourHashSet);
khôn ngoan

65

Thêm tất cả các đối tượng của bạn vào TreeSet, bạn sẽ nhận được một Bộ được sắp xếp. Dưới đây là một ví dụ thô.

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
Bằng cách sử dụng, TreeSet myTreeSet = new TreeSet(myHashSet);bạn có thể tránh thêm lại tất cả các phần tử vào Treeset.
Mounika

17

Bạn có thể sử dụng TreeSet để thay thế.


1
Việc chỉ đặt các phần tử sẽ không mang lại sự linh hoạt trong việc sắp xếp theo bất kỳ thứ tự nào với bất kỳ phần tử nào bên trong nó. Giải pháp trên không.
Jess

15

Cách sắp xếp trong Java 8 sẽ là:

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đó là một ví dụ về cách sắp xếp HashSet của YourItem một cách tự nhiên theo kích thước.

* Collectors.toList()sẽ thu thập kết quả của việc sắp xếp thành một Danh sách mà bạn sẽ cần nắm bắt nóList<Foo> sortedListOfFoo =


Bạn có thể vui lòng, Thêm logic để sắp xếp nó theo một thứ tự cụ thể?
Jess

@Jess Tôi không biết thứ tự cụ thể cho bạn là gì, Jess, bạn có thể sắp xếp nó theo ý muốn bằng cách sử dụng trình so sánh.
LazerBanana

Ý tôi là, làm thế nào để xác định Tăng dần hoặc Giảm dần
Jess

14

Sử dụng java.util.TreeSetnhư đối tượng thực tế. Khi bạn lặp lại bộ sưu tập này, các giá trị sẽ trở lại theo một thứ tự được xác định rõ ràng.

Nếu bạn sử dụng java.util.HashSetthì thứ tự phụ thuộc vào một hàm băm bên trong mà gần như chắc chắn không phải là từ điển (dựa trên nội dung).


Tại sao bạn lại cho rằng họ lưu trữ Stringcác giá trị?
Sotirios Delimanolis

Tôi không mặc dù có lẽ việc sử dụng từ vựng của tôi là không chính xác ;-)
P45 Sắp xảy ra

3
Nó rất sai lầm. Nó không lưu trữ các khóa theo thứ tự từ vựng (sp?). Nó sử dụng thứ tự tự nhiên của chúng (tùy thuộc vào Comparablegiao diện mà các phím triển khai) hoặc sử dụng thứ tự được cung cấp Comparator.
Sotirios Delimanolis

Tôi đã chỉnh sửa. Bạn nghĩ tốt hơn, hay tôi nên xóa câu trả lời?
P45 sắp xảy ra

1
Trong trường hợp bạn chuyển HashSetđến TreeSet, lớp của bạn phải triển khai Comparablegiao diện hoặc cung cấp một tùy chỉnh Comparator. Nếu không, vì bạn không thể sắp xếp a HashSet, chỉ cần chuyển nó thành a Listvà sắp xếp nó.
Luiggi Mendoza

5

Bạn có thể sử dụng bộ sưu tập Java 8 và TreeSet

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


new TreeSet<>(hashSet)ngắn gọn hơn và có lẽ hiệu quả hơn.
devconsole

4

Bạn có thể sử dụng TreeSet như đã đề cập trong các câu trả lời khác.

Dưới đây là một chút chi tiết hơn về cách sử dụng nó:

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

Đầu ra:

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

4

Không thể sắp xếp các phần tử trong HashSet. Bất cứ khi nào bạn đặt các phần tử vào HashSet, nó có thể làm xáo trộn thứ tự của toàn bộ tập hợp. Nó được cố tình thiết kế như vậy để biểu diễn. Khi bạn không quan tâm đến thứ tự, HashSet sẽ là tập hợp hiệu quả nhất để chèn và tìm kiếm nhanh chóng.

TreeSet sẽ tự động sắp xếp tất cả các phần tử mỗi khi bạn chèn một phần tử.

Có lẽ, những gì bạn đang cố gắng làm là sắp xếp chỉ một lần. Trong trường hợp đó, TreeSet không phải là lựa chọn tốt nhất vì nó cần phải xác định vị trí của các phần tử mới được thêm vào mọi lúc.

Giải pháp hiệu quả nhất là sử dụng ArrayList. Tạo một danh sách mới và thêm tất cả các phần tử rồi sắp xếp nó một lần. Nếu bạn chỉ muốn giữ lại các phần tử duy nhất (xóa tất cả các phần tử trùng lặp như set đã làm, sau đó đặt danh sách vào LinkedHashSet, nó sẽ giữ lại thứ tự bạn đã sắp xếp)

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.

Bây giờ, bạn đã có một tập hợp được sắp xếp nếu bạn muốn nó ở dạng danh sách, sau đó chuyển đổi nó thành danh sách.


3

Dựa trên câu trả lời được đưa ra bởi @LazerBanana, tôi sẽ đưa ra ví dụ của riêng tôi về một Bộ được sắp xếp theo Id của Đối tượng:

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

Chỉ trong trường hợp bạn không muốn sử dụng, TreeSetbạn có thể thử cái này.

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

2

Theo ý kiến ​​khiêm tốn của tôi, câu trả lời của LazerBanana nên là câu trả lời được xếp hạng cao nhất và được chấp nhận bởi vì tất cả các câu trả lời khác trỏ đến java.util.TreeSet(hoặc đầu tiên chuyển đổi thành danh sách sau đó gọi Collections.sort(...)vào danh sách được chuyển đổi) đã không bận tâm đến việc hỏi OP là loại đối tượng của bạn HashSetcó nghĩa là gì nếu các phần tử đó có thứ tự tự nhiên được xác định trước hay không & đó không phải là câu hỏi tùy chọn mà là câu hỏi bắt buộc.

Bạn chỉ không thể vào và bắt đầu đưa các HashSetphần tử của mình vào một TreeSetloại phần tử if chưa có Comparablegiao diện triển khai hoặc nếu bạn không chuyển một cách rõ ràng Comparatorđến phương thức TreeSetkhởi tạo.

Từ TreeSetJavaDoc,

Xây dựng một tập hợp cây trống mới, được sắp xếp theo thứ tự tự nhiên của các phần tử của nó. Tất cả các phần tử được chèn vào tập hợp phải triển khai giao diện So sánh được. Hơn nữa, tất cả các phần tử như vậy phải có thể so sánh lẫn nhau: e1.compareTo (e2) không được ném ClassCastException cho bất kỳ phần tử e1 và e2 nào trong tập hợp. Nếu người dùng cố gắng thêm một phần tử vào tập hợp vi phạm ràng buộc này (ví dụ: người dùng cố gắng thêm một phần tử chuỗi vào một tập hợp có các phần tử là số nguyên), thì lệnh gọi thêm sẽ ném ra một ClassCastException.

Đó là lý do tại sao chỉ tất cả các câu trả lời dựa trên luồng Java8 - nơi bạn xác định bộ so sánh của mình ngay tại chỗ - chỉ có ý nghĩa vì việc triển khai có thể so sánh trong POJO trở thành tùy chọn. Lập trình viên định nghĩa bộ so sánh khi cần thiết. Cố gắng thu thập vào TreeSetmà không hỏi câu hỏi cơ bản này cũng không chính xác (câu trả lời của Ninja). Giả sử các loại đối tượng là Stringhoặc Integercũng không chính xác.

Đã nói rằng, những mối quan tâm khác như,

  1. Phân loại Hiệu suất
  2. Memory Foot Print (giữ lại tập hợp ban đầu và tạo tập hợp được sắp xếp mới mỗi khi sắp xếp xong hoặc muốn sắp xếp tập hợp tại chỗ, v.v.)

cũng nên là các điểm liên quan khác. Chỉ trỏ đến API không nên chỉ có ý định.

Vì tập hợp gốc đã chỉ chứa các phần tử duy nhất và ràng buộc đó cũng được duy trì bởi tập hợp đã sắp xếp nên tập hợp ban đầu cần được xóa khỏi bộ nhớ vì dữ liệu được sao chép.


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

đầu vào - ved prakash sharma táo ved chuối

Đầu ra - apple banana prakash sharma ved


1

Nếu bạn muốn phần cuối Collectionở dạng Setvà nếu bạn muốn định nghĩa của riêng bạn natural orderhơn là của TreeSetsau đó -

1. Chuyển HashSetthành List
2. Tùy chỉnh sắp xếp Listbằng cách sử dụng Comparator
3. Chuyển ngược Listthành LinkedHashSetđể duy trì thứ tự
4. Hiển thị LinkedHashSet

Chương trình mẫu -

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

Đầu ra -

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

Ở đây bộ sưu tập đã được sắp xếp theo -

Thứ nhất - Thứ tự Stringđộ dài
giảm dần Thứ hai - Thứ tự giảm dần của Stringhệ thống phân cấp chữ cái


0

bạn có thể làm điều này theo những cách sau:

Phương pháp 1:

  1. Tạo một danh sách và lưu trữ tất cả các giá trị hashset vào đó
  2. sắp xếp danh sách bằng Collections.sort ()
  3. Lưu trữ danh sách trở lại LinkedHashSet vì nó duy trì thứ tự chèn

Phương pháp 2:

  • Tạo một treeSet và lưu trữ tất cả các giá trị vào nó.

Phương pháp 2 thích hợp hơn vì phương pháp kia tiêu tốn nhiều thời gian để chuyển dữ liệu qua lại giữa hashset và list.


0

Chúng tôi không thể quyết định rằng các phần tử của HashSet sẽ được sắp xếp tự động. Nhưng chúng ta có thể sắp xếp chúng bằng cách chuyển đổi thành TreeSet hoặc bất kỳ Danh sách nào như ArrayList hoặc LinkedList, v.v.

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

Bạn có thể sử dụng thư viện ổi cho cùng

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

Bạn có thể bọc nó trong một TreeSet như thế này:

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

đầu ra:
mục mySet [1, 3, 4, 5]
mục 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);

đầu ra:
mục mySet [sáu, bốn, năm, hai, elf]
treeSet mục [elf, năm, bốn, sáu, hai]

yêu cầu đối với phương pháp này là các đối tượng của tập hợp / danh sách phải có thể so sánh được (triển khai giao diện So sánh được)


-4

Lệnh đơn giản này đã thực hiện mẹo cho tôi:

myHashSet.toList.sorted

Tôi đã sử dụng điều này trong một câu lệnh in, vì vậy nếu bạn thực sự cần duy trì thứ tự, bạn có thể cần sử dụng TreeSets hoặc các cấu trúc khác được đề xuất trên luồng này.


1
Tôi không thấy HashSet hoặc Set có phương thức ở đâu toList.
Thomas Eizinger

1
Điều đó trông giống như Scala đối với tôi, không may là không giải quyết được vấn đề trong Java.
Roberto

toList method, Làm thế nào là có thể?
Ved Prakash
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.