Bagaimana cara mempertahankan Daftar Unik di Java?


104

Bagaimana cara membuat daftar objek unik / berbeda (tidak ada duplikat) di Java?

Sekarang saya menggunakan HashMap<String, Integer>untuk melakukan ini karena kuncinya ditimpa dan karenanya pada akhirnya kita bisa mendapatkan HashMap.getKeySet()yang unik. Tapi saya yakin harus ada cara yang lebih baik untuk melakukan ini karena bagian nilai terbuang percuma di sini.

Jawaban:


164

Anda dapat menggunakan implementasi Set :

Beberapa info dari JAVADoc:

Koleksi yang tidak berisi elemen duplikat . Lebih formal, himpunan tidak berisi pasangan elemen e1 dan e2 sehingga e1.equals (e2), dan paling banyak satu elemen null. Seperti yang tersirat dari namanya, antarmuka ini memodelkan abstraksi himpunan matematika.

Catatan: Kehati-hatian harus dilakukan jika objek yang bisa berubah digunakan sebagai elemen set. Perilaku suatu himpunan tidak ditentukan jika nilai suatu objek diubah sedemikian rupa sehingga mempengaruhi perbandingan yang sama sedangkan objek tersebut merupakan elemen dalam himpunan tersebut. Kasus khusus dari larangan ini adalah tidak dibolehkannya set berisi dirinya sendiri sebagai elemen.`

Berikut implementasinya:

  • HashSet

    Kelas ini menawarkan kinerja waktu yang konstan untuk operasi dasar (tambah, hapus, isi, dan ukuran), dengan asumsi fungsi hash menyebarkan elemen dengan benar di antara bucket. Iterasi atas set ini membutuhkan waktu yang sebanding dengan jumlah ukuran instance HashSet (jumlah elemen) ditambah "kapasitas" dari backing instance HashMap (jumlah bucket). Karena itu, sangat penting untuk tidak menyetel kapasitas awal terlalu tinggi (atau faktor beban terlalu rendah) jika kinerja iterasi penting.

    Saat melakukan iterasi HashSet, urutan elemen yang dihasilkan tidak ditentukan.

  • LinkedHashSet

    Tabel hash dan implementasi daftar tertaut dari antarmuka Set, dengan urutan iterasi yang dapat diprediksi. Implementasi ini berbeda dari HashSet karena ia mempertahankan daftar tertaut ganda yang berjalan melalui semua entri. Daftar tertaut ini mendefinisikan pengurutan iterasi, yaitu urutan elemen yang dimasukkan ke dalam set (urutan-penyisipan). Perhatikan bahwa urutan penyisipan tidak terpengaruh jika sebuah elemen dimasukkan kembali ke dalam set. (Sebuah elemen e dimasukkan kembali ke dalam himpunan s jika s.add (e) dipanggil ketika s.contains (e) akan mengembalikan true segera sebelum pemanggilan.)

    Jadi, keluaran dari kode diatas ...

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

    ... tentu saja

    3
    1
    2
    
  • TreeSet

    Implementasi ini memberikan jaminan biaya waktu log (n) untuk operasi dasar (tambah, hapus, dan isi). Secara default elemen he yang dikembalikan pada iterasi diurutkan berdasarkan " pengurutan alami ", jadi kode di atas ...

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

    ... akan menampilkan ini:

    1
    2
    3
    

    (Anda juga dapat meneruskan sebuah Comparatorinstance ke TreeSetkonstruktor, membuatnya mengurutkan elemen dalam urutan yang berbeda.)

    Perhatikan bahwa pengurutan yang dipertahankan oleh suatu set (apakah pembanding eksplisit disediakan atau tidak) harus konsisten dengan sama jika ingin mengimplementasikan antarmuka Set dengan benar. (Lihat Comparable atau Comparator untuk definisi yang tepat tentang konsistensi dengan persamaan.) Hal ini terjadi karena antarmuka Set didefinisikan dalam istilah operasi yang sama, tetapi instance TreeSet melakukan semua perbandingan elemen menggunakan metode bandingkanTo (atau bandingkan), jadi dua elemen yang dianggap sama dengan metode ini, dari sudut pandang himpunan, sama. Perilaku himpunan terdefinisi dengan baik meskipun urutannya tidak konsisten dengan sama; itu hanya gagal untuk mematuhi kontrak umum dari antarmuka Set.


Sekarang saya bingung, mana yang harus saya gunakan? Saya hanya perlu memiliki daftar string unik. Jadi pada dasarnya bahkan ketika string yang ada ditambahkan itu sebenarnya harus ditambahkan.

1
Pilihan ada di tangan Anda ... HashSet bersifat universal dan cepat, kumpulan pohon dipesan, LinkedHashset menjaga urutan penyisipan ...
Frank

6
Ini bukan LIST ... jadi, tidak semua metode antarmuka LIST tersedia.
marcolopes

2
Satu set bukan daftar, saya tidak bisa mencari elemen dengan indeks dalam satu set dalam waktu O (1) (akses acak).
wilmol

13

Saya ingin mengklarifikasi beberapa hal di sini untuk poster asli yang telah disinggung orang lain tetapi belum dinyatakan secara eksplisit. Saat Anda mengatakan bahwa Anda menginginkan daftar unik, itulah definisi dari Kumpulan Berurutan. Beberapa perbedaan utama lainnya antara Antarmuka Set dan Antarmuka Daftar adalah bahwa Daftar memungkinkan Anda menentukan indeks penyisipan. Jadi, pertanyaannya adalah apakah Anda benar-benar membutuhkan Antarmuka Daftar (yaitu untuk kompatibilitas dengan pustaka pihak ketiga, dll.), Atau dapatkah Anda mendesain ulang perangkat lunak Anda untuk menggunakan antarmuka Set? Anda juga harus mempertimbangkan apa yang Anda lakukan dengan antarmuka. Apakah penting untuk menemukan elemen berdasarkan indeksnya? Berapa banyak elemen yang Anda harapkan di set Anda? Jika Anda ingin memiliki banyak elemen, apakah pemesanan itu penting?

Jika Anda benar-benar membutuhkan Daftar yang hanya memiliki batasan unik, ada kelas Apache Common Utils org.apache.commons.collections.list.SetUniqueList yang akan memberi Anda antarmuka Daftar dan batasan unik. Pikiran Anda, ini merusak antarmuka Daftar. Namun, Anda akan mendapatkan kinerja yang lebih baik dari ini jika Anda perlu mencari ke dalam daftar berdasarkan indeks. Jika Anda dapat menggunakan antarmuka Set, dan Anda memiliki kumpulan data yang lebih kecil, LinkedHashSet mungkin merupakan cara yang baik untuk digunakan. Itu hanya tergantung pada desain dan tujuan perangkat lunak Anda.

Sekali lagi, ada kelebihan dan kekurangan masing-masing koleksi. Beberapa sisipan cepat tetapi pembacaan lambat, beberapa memiliki pembacaan cepat tetapi sisipan lambat, dll. Masuk akal untuk meluangkan cukup banyak waktu dengan dokumentasi koleksi untuk mempelajari detail yang lebih baik dari setiap kelas dan antarmuka.


3
Ini tidak memberikan jawaban atas pertanyaan tersebut. Untuk mengkritik atau meminta klarifikasi dari seorang penulis, tinggalkan komentar di bawah kiriman mereka - Anda selalu dapat mengomentari kiriman Anda sendiri, dan setelah Anda memiliki reputasi yang memadai, Anda akan dapat mengomentari kiriman apa pun .
Zach Saucier

1
Sebenarnya itu memberikan jawaban. Jika dia hanya ingin daftar yang bertindak seperti Set, gunakan org.apache.commons.collections.list.SetUniqueList, tetapi sebagai programmer, dia / kita harus lebih berhati-hati daripada itu dan harus lebih memikirkan masalahnya. Jika ini membuat jawaban saya lebih baik, "Bagaimana cara membuat Daftar Unik di Java?" Daftar uniqueList = new SetUniqueList () ;, begitulah ....
Paul Connolly

3
Dan Zach, saya tidak mencoba menjadi orang brengsek, tetapi apakah Anda bahkan membaca jawaban saya sebelum komentar Anda? Atau apakah Anda tidak memahaminya? Jika Anda tidak memahaminya, tidak apa-apa - beri tahu saya dan saya akan memperluas topiknya. Saya tidak berpikir saya harus menulis risalah tentang struktur data untuk memberikan jawaban ramah atas pertanyaan seseorang. Saya juga tidak peduli untuk melakukan cara yang lembut untuk membangun reputasi komentar saya ketika saya tahu jawabannya dan tidak ada orang lain yang benar-benar memberikannya.
Paul Connolly

1
Dan omong-omong, saya tidak mengkritik atau meminta klarifikasi dari penulis, saya hanya mengatakan bahwa dia dapat A) dengan cepat menggunakan kelas yang saya berikan kepadanya, atau B) meluangkan waktu untuk benar-benar memahami perbedaan antara kelas-kelas ini dan berhubungan mereka untuk kebutuhannya. B jelas membutuhkan waktu lebih lama, tetapi akan menghasilkan kode yang lebih baik dalam jangka panjang.
Paul Connolly

8

Gunakan new HashSet<String> Contoh:

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
Hanya menambahkan program di atas -> 11 surat harus dikirim ke: [Aaron, Alice, James, Adel, Jose, Jeremy, Amy, Alan, Patrick, Helen, Alexi]
Ammad

4

Anda bisa menggunakan a HashSet<String>untuk memelihara koleksi objek unik. Jika Integernilai di peta Anda penting, Anda dapat menggunakan containsKeymetode maps untuk menguji apakah kunci Anda sudah ada di peta.


3

HashSet<String>(atau) Setimplementasi apa pun dapat melakukan pekerjaan itu untuk Anda. Setjangan izinkan duplikat.

Berikut adalah javadoc untuk HashSet.


2

Saya tidak tahu seberapa efisien ini, Namun berhasil untuk saya dalam konteks yang sederhana.

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

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

1

Anda mungkin ingin menggunakan salah satu kelas pelaksana java.util.Set<E>Antarmuka misalnya java.util.HashSet<String> kelas koleksi.

Koleksi yang tidak berisi elemen duplikat. Lebih formal, himpunan tidak berisi pasangan elemen e1 dan e2 sehingga e1.equals (e2), dan paling banyak satu elemen null. Seperti yang tersirat dari namanya, antarmuka ini memodelkan abstraksi himpunan matematika.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.