Java'da Benzersiz Liste nasıl tutulur?


104

Java'da benzersiz / farklı nesnelerin bir listesi (yineleme olmadan) nasıl oluşturulur?

Şu anda bunu HashMap<String, Integer>yapmak için kullanıyorum çünkü anahtarın üzerine yazılır ve bu nedenle sonunda HashMap.getKeySet()hangisinin benzersiz olacağını elde edebiliriz . Ama eminim bunu yapmanın daha iyi bir yolu olmalı çünkü burada değer kısmı boşa gidiyor.

Yanıtlar:


165

Bir Set uygulaması kullanabilirsiniz :

JAVADoc'tan bazı bilgiler:

Yinelenen öğeler içermeyen bir koleksiyon . Daha biçimsel olarak, kümeler e1.equals (e2) gibi hiçbir e1 ve e2 öğesi ve en fazla bir boş öğe içermez. Adından da anlaşılacağı gibi, bu arayüz matematiksel küme soyutlamasını modellemektedir.

Not: Değişken nesneler set öğeleri olarak kullanılıyorsa büyük özen gösterilmelidir. Bir nesnenin değeri, nesne kümedeki bir öğe iken eşit karşılaştırmaları etkileyecek şekilde değiştirilirse, kümenin davranışı belirtilmez. Bu yasağın özel bir durumu, bir setin kendisini bir unsur olarak içermesine izin verilmez olmasıdır. '

Uygulamalar şunlardır:

  • HashSet

    Bu sınıf, karma işlevinin öğeleri kovalar arasında düzgün bir şekilde dağıttığını varsayarak, temel işlemler (ekleme, kaldırma, içerme ve boyutlandırma) için sabit zaman performansı sunar. Bu set üzerinde yineleme, HashSet örneğinin boyutu (öğe sayısı) artı HashMap örneğinin "kapasitesi" (paket sayısı) toplamıyla orantılı zaman gerektirir. Bu nedenle, yineleme performansı önemliyse başlangıç ​​kapasitesini çok yüksek (veya yük faktörünü çok düşük) ayarlamamak çok önemlidir.

    Bir yineleme HashSetyapıldığında, verilen öğelerin sırası tanımsızdır.

  • LinkedHashSet

    Tahmin edilebilir yineleme sırasına sahip Set arayüzünün karma tablosu ve bağlantılı liste uygulaması. Bu uygulama HashSet'ten farklıdır, çünkü tüm girişleri boyunca çalışan çift bağlantılı bir liste tutar. Bu bağlantılı liste, öğelerin kümeye eklendiği sıra olan yineleme sıralamasını tanımlar (ekleme sırası). Kümeye bir öğe yeniden eklenirse ekleme siparişinin etkilenmeyeceğini unutmayın. (S.add (e), s.contains (e) çağrılmadan hemen önce true döndürürse, bir e öğesi s kümesine yeniden eklenir.)

    Yani yukarıdaki kodun çıktısı ...

     Set<Integer> linkedHashSet = new LinkedHashSet<>();
     linkedHashSet.add(3);
     linkedHashSet.add(1);
     linkedHashSet.add(2);
    
     for (int i : linkedHashSet) {
         System.out.println(i);
     }

    ... mutlaka olacak

    3
    1
    2
  • Ağaç Kümesi

    Bu uygulama, temel işlemler (ekleme, kaldırma ve içeren) için garantili günlük (n) zaman maliyeti sağlar. Varsayılan olarak, yinelemede döndürülen öğeler " doğal sıralamalarına " göre sıralanır , bu nedenle yukarıdaki kod ...

     Set<Integer> treeSet = new TreeSet<>();
     treeSet.add(3);
     treeSet.add(1);
     treeSet.add(2);
    
     for (int i : treeSet) {
         System.out.println(i);
     }

    ... şunu çıkarır:

    1
    2
    3

    (Bir kurucuya bir Comparatorörnek de iletebilir TreeSet, böylece öğeleri farklı bir sırada sıralayabilirsiniz.)

    Bir küme tarafından tutulan sıralamanın (açık bir karşılaştırıcı sağlanmış olsun veya olmasın), Set arabirimini doğru bir şekilde uygulamak için eşitler ile tutarlı olması gerektiğini unutmayın. (Eşittir ile tutarlılık kesin bir tanımı için Karşılaştırılabilir veya Karşılaştırıcı'ya bakın.) Bunun nedeni, Set arabiriminin eşittir işlemi açısından tanımlanmasıdır, ancak bir TreeSet örneği, tüm öğe karşılaştırmalarını kendi karşılaştırma (veya karşılaştırma) yöntemini kullanarak gerçekleştirir, bu nedenle iki Bu yöntemle eşit kabul edilen öğeler, küme açısından eşittir. Bir kümenin davranışı, sıralaması eşitler ile tutarsız olsa bile iyi tanımlanmıştır; sadece Set arayüzünün genel sözleşmesine uymaz.


Şimdi kafam karıştı, hangisini kullanmalıyım? Sadece benzersiz dizelerin bir listesini tutmam gerekiyor. Yani temelde var olan bir dizge eklendiğinde bile aslında eklenmelidir.

1
Seçim sizin ... HashSet evrensel ve hızlıdır, ağaç seti sipariş edilir, LinkedHashset ekleme sırasını tutar ...
Frank

6
Bu bir LİSTE değil ... bu nedenle, tüm LIST arabirim yöntemleri kullanılamaz.
marcolopes

2
Bir küme bir liste değil, O (1) zamanı (rasgele erişim) içindeki bir küme içindeki elemanları dizine göre arayamıyorum.
wilmol

13

Başkalarının ima ettiği ancak gerçekten açıkça belirtmediği orijinal poster için burada bazı şeyleri açıklığa kavuşturmak istiyorum. Bir Benzersiz Liste istediğinizi söylediğinizde, Sıralı Kümenin tanımı budur. Set Interface ve List arayüzü arasındaki diğer bazı önemli farklar, List'in ekleme indeksini belirlemenize izin vermesidir. Öyleyse soru şu: Liste Arayüzüne gerçekten ihtiyacınız var mı? Ayrıca arayüzle ne yaptığınızı da düşünmelisiniz. Öğeleri indekslerine göre bulmak önemli mi? Setinizde kaç element bekliyorsunuz? Çok sayıda öğeniz olacaksa, sipariş vermek önemli mi?

Yalnızca benzersiz bir kısıtı olan bir Listeye gerçekten ihtiyacınız varsa, size List arabirimini ve benzersiz kısıtı sağlayacak olan Apache Common Utils org.apache.commons.collections.list.SetUniqueList sınıfı vardır. Dikkat edin, bu liste arayüzünü bozar. Bununla birlikte, listeye dizine göre bakmanız gerekirse, bundan daha iyi performans elde edersiniz. Set arayüzüyle başa çıkabiliyorsanız ve daha küçük bir veri kümeniz varsa, LinkedHashSet gitmek için iyi bir yol olabilir. Bu sadece yazılımınızın tasarımına ve amacına bağlıdır.

Yine, her koleksiyonun belirli avantajları ve dezavantajları vardır. Bazı hızlı eklemeler, ancak yavaş okumalar, bazılarında hızlı okumalar ancak yavaş eklemeler, vb. Her bir sınıfın ve arayüzün daha ince ayrıntılarını tam olarak öğrenmek için koleksiyon belgelerine oldukça fazla zaman harcamak mantıklıdır.


3
Bu soruya bir cevap vermiyor. Bir yazarı eleştirmek veya açıklama istemek için, gönderisinin altına bir yorum bırakın - kendi gönderilerinize her zaman yorum yapabilirsiniz ve yeterli itibara sahip olduğunuzda herhangi bir gönderi hakkında yorum yapabilirsiniz .
Zach Saucier

1
Aslında bir cevap veriyor. Küme gibi davranan bir liste istiyorsa, org.apache.commons.collections.list.SetUniqueList'i kullanın, ancak bir programcı olarak bundan daha dikkatli olmalı ve sorun hakkında daha fazla düşünmeliyiz. Bu, cevabımı daha iyi hale getirirse, "Java'da Benzersiz Liste nasıl oluşturulur?" List uniqueList = new SetUniqueList (); işte böyle ....
Paul Connolly

3
Ve Zach, aptal olmaya çalışmıyorum ama yorumundan önce cevabımı okudun mu? Yoksa anlamıyor musun? Anlamıyorsanız, sorun değil - bana bildirin, konuyu genişleteyim. Birinin sorusuna dostane bir yanıt vermek için veri yapıları üzerine bir inceleme yazmam gerektiğini düşünmüyorum. Yanıtı bildiğimde ve başka hiç kimse gerçekten sağlamadığında, yorum itibarımı oluşturmanın uysal bir yolunu da umursamıyorum.
Paul Connolly

1
Ve bu arada, yazardan ne eleştiriyor ne de açıklama istemiyordum, sadece A) ona verdiğim sınıfı hızlıca kullanabileceğini ya da B) bu sınıflar arasındaki farkları gerçekten anlamak ve ilişki kurmak için zaman ayırabileceğini söylüyordum. ihtiyaçları için. B açıkça daha uzun sürer, ancak uzun vadede daha iyi kodla sonuçlanacaktır.
Paul Connolly

9

new HashSet<String> Bir örnek kullanın :

import java.util.HashSet;
import java.util.Set;

public class MainClass {
  public static void main(String args[]) {
    String[] name1 = { "Amy", "Jose", "Jeremy", "Alice", "Patrick" };

    String[] name2 = { "Alan", "Amy", "Jeremy", "Helen", "Alexi" };

    String[] name3 = { "Adel", "Aaron", "Amy", "James", "Alice" };

    Set<String> letter = new HashSet<String>();

    for (int i = 0; i < name1.length; i++)
      letter.add(name1[i]);

    for (int j = 0; j < name2.length; j++)
      letter.add(name2[j]);

    for (int k = 0; k < name3.length; k++)
      letter.add(name3[k]);

    System.out.println(letter.size() + " letters must be sent to: " + letter);

  }
}

2
Sadece yukarıdaki programı ekleyerek -> 11 mektup şu
adrese

4

Bir HashSet<String>benzersiz nesneler koleksiyonunu korumak için sadece a kullanabilirsiniz . Eğer Integerharitanızda değerler önemlidir, o zaman bunun yerine kullanabilirsiniz containsKeyanahtar haritası zaten olup olmadığını test etmek haritaların yöntemini.


3

HashSet<String>(veya) herhangi bir Setuygulama işi sizin için yapabilir. Setkopyalara izin verme.

İşte HashSet için javadoc .


2

Bunun ne kadar verimli olduğunu bilmiyorum, Ancak basit bir bağlamda benim için çalıştı.

List<int> uniqueNumbers = new ArrayList<>();

   public void AddNumberToList(int num)
    {
        if(!uniqueNumbers .contains(num)) {
            uniqueNumbers .add(num);
        }
    }

1

java.util.Set<E>Arayüz uygulama sınıflarından birini, örneğin java.util.HashSet<String> koleksiyon sınıfını kullanmak isteyebilirsiniz .

Yinelenen öğeler içermeyen bir koleksiyon. Daha biçimsel olarak, kümeler e1.equals (e2) gibi hiçbir e1 ve e2 öğesi ve en fazla bir boş öğe içermez. Adından da anlaşılacağı gibi, bu arayüz matematiksel küme soyutlamasını modellemektedir.

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.