Kümeyi koruyan ve Listeyi de uygulayan bir ekleme siparişi var mı?


85

Ben bir uygulamasını bulmaya çalışıyorum java.util.Listve java.util.SetJava aynı anda. Bu sınıfın yalnızca benzersiz öğelere (as Set) izin vermesini ve sıralarını (gibi List) korumasını istiyorum . JDK 6'da var mı?

List<T>#add(int, T)Belirli bir pozisyona girebilmem için sahip olmak önemlidir .


Kampanya siparişlerini mi yoksa a ile tanımlanan bazı siparişleri mi korumak istiyorsunuz Comparator? Ayrıca Listarayüzün anlambilimini de istiyor musunuz?

Yanıtlar:


208

TreeSetöğe sırasına göre sıralanır; LinkedHashSetkampanya siparişini tutar. Umarım peşinde olduğun şey bunlardan biridir.

Rasgele bir yere yerleştirmek istediğinizi belirttiniz , sanırım kendinizinkini yazmanız gerekecek - sadece a HashSet<T>ve an içeren bir sınıf oluşturun ArrayList<T>; bir öğe eklerken, onu listeye eklemeden önce kümede olup olmadığını kontrol edin.

Alternatif Apache commons-collections4 teklifler ListOrderedSetve SetUniqueListbenzer şekilde davranan ve verilen gereksinimleri karşılaması gerekir.



12

Beğendin mi LinkedHashSet? Bu, giriş sırasını korur, ancak kopyalara izin vermez.

IMHO, alışılmadık bir gereksinimdir, ancak kopyalar olmadan bir Liste yazabilirsiniz.

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

ListArayüzü uygulamıyor , soruda yaptığım değişiklikleri görün
yegor256

2
stackoverflow.com/a/8185105/253468 , O(n)ekleme karmaşıklığına sahip olmadığı için daha iyi görünüyor , çift depolama ve O(log(n))ekleme işlemi arasında göz önünde bulundurulması gereken bir değiş tokuş var .
TWiStErRob

8

Sen uygulayamaz Listve Setsözleşme ihlali olmadan bir kerede. Örneğin, Set.hashCodesözleşmeye bakınız:

Bir kümenin karma kodu, kümedeki öğelerin karma kodlarının toplamı olarak tanımlanır, burada bir boş öğenin karma kodu sıfır olarak tanımlanır.

Öte yandan, sözleşmesi şu şekildedir List.hashCode:

Bir listenin karma kodu aşağıdaki hesaplamanın sonucu olarak tanımlanır:

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

Bu nedenle, her iki sözleşmenin de yerine getirilmesini garanti eden tek bir sınıf uygulamak imkansızdır. Uygulama için aynı sorun equals.



0

Benim de benzer bir problemim vardı, bu yüzden kendim yazdım. Buraya bakın . IndexedArraySetUzanır ArrayListve uygular Seto tüm bu gerekir operasyonları desteklemeli, böylece. ArrayListAşağıdaki tüm öğelerin taşınması gerektiğinden, büyük listeler için öğelerin ortasındaki konumlara öğe eklemenin yavaş olabileceğini unutmayın. Benim IndexedArraySetbunu değiştirmezim.


0

Başka bir seçenek (eksi Listarayüz gereksinimi), ImmutableSetekleme sırasını koruyan Guava'nınkidir. Gönderen onların wiki sayfasından :

Sıralanmış koleksiyonlar haricinde, sipariş yapım süresinden itibaren korunur. Örneğin,

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

"a", "b", "c", "d" sırasıyla öğeleri üzerinde yineleme yapacaktır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.