pertanyaan
Saat ini, teknologi internet matang, dan semakin banyak cenderung terdesentralisasi, didistribusikan, dan streaming komputasi, yang telah menempatkan banyak hal yang telah dilakukan di sisi basis data di sisi Java. Hari ini seseorang bertanya, apakah bidang database tidak memiliki indeks, bagaimana seharusnya dideduplikasi berdasarkan bidang? Semua orang setuju untuk menggunakan Java untuk melakukannya, tetapi bagaimana melakukannya?
menjawab
Tiba -tiba saya ingat artikel yang saya tulis dalam daftar untuk menghilangkan beban berat sebelumnya, dan menemukannya dan membacanya. Metode ini adalah menulis ulang kode hash dan sama dengan metode objek dalam daftar, melemparkannya ke hashset, dan kemudian mengeluarkannya. Ini adalah jawaban yang saya tulis seperti kamus ketika saya pertama kali belajar Java. Misalnya, ketika wawancara, orang -orang yang telah berada di Java selama 3 tahun, mereka dapat menghafal perbedaan antara set dan hashmap, tetapi mereka tidak tahu bagaimana mengimplementasikannya. Dengan kata lain, pemula hanya menghafal karakteristik. Tetapi ketika Anda benar -benar menggunakannya dalam suatu proyek, Anda perlu memastikan itu benar. Karena dukungan tidak berguna, saya hanya bisa percaya pada hasilnya. Anda perlu tahu bagaimana Hashset dapat membantu saya menyingkirkan beban yang berat. Jika Anda memikirkannya, dapatkah Anda menghapus beban berat tanpa hashset? Cara paling sederhana dan paling langsung adalah membandingkannya dengan data historis setiap kali, dan memasukkannya ke dalam ekor antrian jika berbeda. Dan hashset hanya mempercepat proses ini.
Pertama, berikan pengguna objek untuk mengurutkan
@Data@builder@allArgsconstructorPublic kelas pengguna {private integer ID; nama string pribadi;} Daftar <User> user = lists.newarraylist (pengguna baru (1, "a"), pengguna baru (1, "b"), pengguna baru (2, "b"), pengguna baru (1, "a"));Tujuannya adalah untuk mengambil pengguna tanpa duplikat ID. Untuk mencegah pertengkaran, saya memberikan aturan. Ambil saja data dengan ID unik sesuka hati, dan tidak harus berhati -hati tentang mana yang dihitung ketika ID sama.
Gunakan metode yang paling intuitif
Metode ini adalah menggunakan daftar kosong untuk menyimpan data yang dilintasi.
@Testpublic void dis1 () {list <user> result = new LinkedList <> (); untuk (pengguna pengguna: pengguna) {boolean b = result.stream (). anymatch (u -> u.getId (). Equals (user.getId ())); if (! b) {result.add (pengguna); }} System.out.println (hasil);}Gunakan hashset
Siapa pun yang telah menghafal fitur -fitur itu tahu bahwa hashset dapat menghilangkan beban berat, jadi bagaimana cara menghilangkan beban berat? Menghafalnya sedikit lebih dalam dan menurut kode hashcode dan sama dengan metode. Jadi, bagaimana berdasarkan keduanya? Orang -orang yang belum membaca kode sumber tidak dapat dilanjutkan, dan wawancara berakhir di sini.
Faktanya, Hashset diimplementasikan oleh HashMap (saya belum pernah melihat kode sumber dan saya selalu secara intuitif berpikir bahwa kunci hashmap diimplementasikan oleh hashset, yang justru sebaliknya). Saya tidak akan memperluas deskripsi di sini, lihat saja metode konstruksi dan tambahkan metode hashset untuk dipahami.
hashset publik () {peta = hashmap baru <> ();}/*** Jelas, jika ada, ia mengembalikan false, jika tidak ada, ia mengembalikan true*/public boolean add (e e) {return map.put (e, present) == null;}Kemudian, juga dapat dilihat dari ini bahwa pengulangan hashset diimplementasikan berdasarkan hashmap, dan implementasi hashMap sepenuhnya bergantung pada kode hashcode dan sama dengan metode. Sekarang benar -benar dibuka. Jika Anda ingin menggunakan Hashset, Anda harus optimis tentang kedua metode Anda.
Dalam pertanyaan ini, kita perlu deduplikat berdasarkan ID, jadi basis perbandingan kami adalah ID. Modifikasi adalah sebagai berikut:
@Overridepublic Boolean sama (objek o) {if (this == o) {return true; } if (o == null || getClass ()! = o.getClass ()) {return false; } Pengguna pengguna = (pengguna) o; return objects.equals (id, user.id);}@overridepublic int hashCode () {return objects.hash (id);} // hashcoderesult = 31 * hasil + (elemen == null? 0: element.hashCode ());Di antara mereka, objek menyebut array 'HashCode, dan kontennya seperti yang ditunjukkan di atas. Kalikan dengan 31 sama dengan x << 5-x.
Implementasi akhir adalah sebagai berikut:
@Testpublic void dis2 () {set <user> result = hashset baru <> (pengguna); System.out.println (hasil);}Gunakan stream java untuk deduplikat
Kembali ke pertanyaan awal, alasan untuk mengajukan pertanyaan ini adalah bahwa jika Anda ingin kembali ke sisi basis data ke sisi Java, jumlah data mungkin relatif besar, seperti 100.000 buah. Untuk data besar, menggunakan fungsi yang berhubungan dengan aliran adalah yang termudah. Sama seperti Stream juga menyediakan fungsi yang berbeda. Jadi bagaimana seharusnya digunakan?
Users.parallelstream (). Difiste (). foreach (System.out :: println);
Saya tidak melihat Lambda sebagai parameter, yaitu, tidak ada kondisi khusus yang disediakan. Untungnya, Javadoc menandai standar deduplikasi:
Mengembalikan aliran yang terdiri dari elemen yang berbeda (sesuai dengan {@link objek#sama (objek)}) dari aliran ini.Kita tahu bahwa kita juga harus menghafal prinsip ini: ketika sama dengan pengembalian true, nilai pengembalian kode hash harus sama. Ini sedikit membingungkan saat menghafal, tetapi selama kita memahami metode implementasi hashmap, kita tidak akan merasa sulit untuk berbicara. HashMap pertama -tama menempatkan sesuai dengan metode kode hash, dan kemudian membandingkan metode Equals.
Oleh karena itu, untuk menggunakan berbeda untuk mencapai deduplikasi, Anda harus mengganti kode hash dan sama dengan metode kecuali Anda menggunakan yang default.
Jadi, mengapa Anda melakukan ini? Klik dan lihat implementasinya.
<p_in> simpul <T> redukir (PipelineHelper <T> helper, spliterator <p_in> spliterator) {// Jika aliran diurutkan maka itu juga harus dipesan sehingga hal berikut juga akan // menjaga terminal orde, LinkedHashset <T> DEXITOP = pengurangan. LinkedHashset :: Add, LinkedHashset :: Addall); return nodes.node (rediceop.evaluateParallel (helper, splitterator));}Internal diimplementasikan menggunakan pengurangan. Ketika Anda berpikir untuk berkurang, Anda langsung memikirkan metode untuk mengimplementasikan DistanceBykey sendiri. Saya hanya perlu menggunakan pengurangan, dan bagian perhitungannya adalah untuk membandingkan elemen aliran dengan hashmap bawaan, lewati jika ada, dan masukkan jika tidak ada. Faktanya, idenya adalah metode yang paling mudah di awal.
@Testpublic void dis3 () {Users.parallelstream (). Filter (DistanceByKey (user :: getId)) .foreach (System.out :: println);} public static <T> predikat <T> DistancheBykey (function <? Super t,?> KeyExtractor) {set <Object> See = concurrHaseMap.) return t -> see.add (keyextractor.Apply (t));}Tentu saja, jika itu adalah aliran paralel, yang diambil belum tentu yang pertama, tetapi acak.
Metode di atas adalah yang terbaik ditemukan dan tidak invasif. Tetapi jika Anda harus menggunakan berbeda. Anda hanya dapat menulis ulang kode hash dan sama seperti metode hashset.
ringkasan
Anda hanya dapat berlatih apakah Anda dapat menggunakan hal -hal ini sendiri. Kalau tidak, akan sulit untuk mengeluarkannya sekaligus ketika Anda benar -benar ingin menggunakannya, atau Anda akan mengambil risikonya. Dan jika Anda benar -benar ingin menggunakannya dengan berani, juga perlu untuk memahami aturan dan prinsip implementasi. Misalnya, bagaimana implementasi LinkedHashset dan hashset berbeda?
Dilampirkan dengan kode sumber LinkedHashset sederhana:
Kelas Publik LinkedHashset <E> Memperluas HashSet <E> Implement Set <E>, CLONABLE, JAVA.IO.Serializable {Private Static Final Long SerialVersionuid = -285166767971038690L; public linkedHashSet (int initialcapacity, float loadfactor) {super (initialcapacity, loadfactor, true); } public linkedHashSet (int initialcapacity) {super (initialcapacity, .75f, true); } public linkedHashSet () {super (16, .75f, true); } public linkedHashSet (koleksi <? Extends e> c) {super (math.max (2*c.size (), 11), .75f, true); addall (c); } @Override Public Spliterator <E> spliterator () {return spliterators.spliterator (this, spliterator.distinct | spliterator.ordered); }}Mengisi kembali:
Metode untuk menghapus data duplikat dari pengumpulan daftar di java
1. Loop semua elemen dalam daftar dan kemudian hapus duplikat
Daftar statis publik dihapusPlicate (daftar daftar) {for (int i = 0; i <list.size () - 1; i ++) {for (int j = list.size () - 1; j> i; j -) {if (list.get (j) .equals (list.get (i))) {list.remove (j); }}} daftar pengembalian; } 2. Kick Off Elemen Duplikat Melalui Hashset
Daftar Statis Publik dihapusPlicate (daftar daftar) {hashset h = hashset baru (daftar); list.clear (); list.addall (h); daftar pengembalian; }3. Hapus elemen duplikat di Daftar Array untuk menjaga pesanan
// hapus elemen duplikat di arraylist, tetap pesanan public static void dihapusPlicateWithOrder (daftar daftar) {set set = new hashset (); Daftar newList = new arraylist (); untuk (iterator iter = list.iterator (); iter.hasnext ();) {objek elemen = iter.next (); if (set.add (elemen)) newList.add (elemen); } list.clear (); list.addall (newList); System.out.println ("Hapus Duplikat" + Daftar); }4. Iterasi di atas objek dalam daftar, gunakan daftar.contain (), dan jika tidak ada, masukkan ke dalam koleksi daftar lain.
Daftar statis publik dihapusPlicate (daftar daftar) {daftar listTemp = arraylist baru (); untuk (int i = 0; i <list.size (); i ++) {if (! listTemp.contains (list.get (i))) {listtemp.add (list.get (i)); }} return listTemp; }