Có một thứ tự chèn bảo toàn Set cũng thực hiện Danh sách không?


84

Tôi đang cố gắng để tìm một thực hiện java.util.Listjava.util.Settại cùng một thời gian trong Java. Tôi muốn lớp này chỉ cho phép các phần tử duy nhất (as Set) và bảo toàn thứ tự của chúng (như List). Nó có tồn tại trong JDK 6 không?

Điều quan trọng là phải có List<T>#add(int, T)để tôi có thể chèn vào một vị trí cụ thể.


Ý bạn là giữ nguyên thứ tự chèn của chúng hay một số thứ tự được xác định bởi a Comparator? Ngoài ra, bạn có muốn cả ngữ nghĩa của Listgiao diện không?

Câu trả lời:


207

TreeSetđược sắp xếp theo thứ tự phần tử; LinkedHashSetgiữ lại thứ tự chèn. Hy vọng rằng một trong những điều đó là những gì bạn đang có.

Bạn đã chỉ định rằng bạn muốn có thể chèn vào một vị trí tùy ý , tôi nghi ngờ bạn sẽ phải viết của riêng bạn - chỉ cần tạo một lớp có chứa a HashSet<T>và an ArrayList<T>; khi thêm một mục, hãy kiểm tra xem nó có trong tập hợp hay không trước khi thêm nó vào danh sách.

Ngoài ra, commons-collection4 của Apache cung cấp ListOrderedSetSetUniqueList, hoạt động tương tự và phải đáp ứng các yêu cầu nhất định.



12

Bạn có nghĩa là thích LinkedHashSet? Điều này bảo toàn thứ tự của mục nhập, nhưng không cho phép trùng lặp.

IMHO, đó là một yêu cầu bất thường nhưng bạn có thể viết một Danh sách mà không có bản sao.

class SetList<T> extends ArrayList<T> {
    @Override
    public boolean add(T t) {
        return !super.contains(t) && super.add(t);
    }

    @Override
    public void add(int index, T element) {
        if (!super.contains(element)) super.add(index, element);
    }

    @Override
    public boolean addAll(Collection<? extends T> c) {
        boolean added = false;
        for (T t : c)
            added |= add(t);
        return added;
    }

    @Override
    public boolean addAll(int index, Collection<? extends T> c) {
        boolean added = false;
        for (T t : c)
            if (!super.contains(t)) {
                super.add(index++, t);
                added = true;
            }
        return added;
    }
}

Nó không thực hiện Listgiao diện, xem thay đổi của tôi cho câu hỏi
yegor256

2
stackoverflow.com/a/8185105/253468 trông đẹp hơn vì nó không có O(n)độ phức tạp của việc chèn, có một sự cân bằng mà người ta phải cân nhắc giữa lưu trữ kép và O(log(n))hoạt động chèn.
TWiStErRob

8

Bạn không thể thực hiện ListSetngay lập tức mà không vi phạm hợp đồng. Ví dụ, hãy xem Set.hashCodehợp đồng:

Mã băm của một tập hợp được định nghĩa là tổng các mã băm của các phần tử trong tập hợp, trong đó mã băm của một phần tử rỗng được xác định bằng không.

Mặt khác, đây là hợp đồng của List.hashCode:

Mã băm của danh sách được xác định là kết quả của phép tính sau:

int hashCode = 1;
for (E e : list)
    hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());

Vì vậy, không thể thực hiện một lớp duy nhất đảm bảo cả hai hợp đồng được thực hiện. Vấn đề tương tự để equalsthực hiện.



0

Tôi đã có một vấn đề tương tự, vì vậy tôi đã viết của riêng tôi. Xem tại đây . Các IndexedArraySetmở rộng ArrayListvà thực hiện Set, vì vậy nó cần hỗ trợ tất cả các hoạt động mà bạn cần. Lưu ý rằng việc chèn các phần tử vào các vị trí ở giữa một ArrayListdanh sách lớn có thể chậm vì tất cả các phần tử sau đây cần phải được chuyển qua. Của tôi IndexedArraySetkhông thay đổi điều đó.


0

Một tùy chọn khác (trừ Listyêu cầu về giao diện) là Guava's ImmutableSet, giữ nguyên thứ tự chèn. Từ trang wiki của họ :

Ngoại trừ các bộ sưu tập đã được sắp xếp, thứ tự được giữ nguyên từ thời điểm xây dựng. Ví dụ,

ImmutableSet.of("a", "b", "c", "a", "d", "b")

sẽ lặp qua các phần tử của nó theo thứ tự "a", "b", "c", "d".

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.