คำถาม
ทุกวันนี้เทคโนโลยีอินเทอร์เน็ตเป็นผู้ใหญ่และมีแนวโน้มที่จะมีการกระจายอำนาจกระจายและสตรีมคอมพิวเตอร์มากขึ้นเรื่อย ๆ วันนี้มีคนถามว่าฟิลด์ฐานข้อมูลไม่มีดัชนีหรือไม่จะได้รับการหักสำรองตามฟิลด์อย่างไร ทุกคนตกลงที่จะใช้ Java เพื่อทำ แต่จะทำอย่างไร?
คำตอบ
ทันใดนั้นฉันก็จำบทความที่ฉันเขียนไว้ในรายการเพื่อลบน้ำหนักหนักหนักมาก่อนและพบและอ่านมัน วิธีนี้คือการเขียนวิธี HashCode และวิธีการเท่ากับของวัตถุในรายการโยนลงใน HashSet แล้วนำออกมา นี่คือคำตอบที่ฉันเขียนเหมือนพจนานุกรมเมื่อฉันเรียนรู้ Java เป็นครั้งแรก ตัวอย่างเช่นเมื่อสัมภาษณ์คนที่อยู่ในชวาเป็นเวลา 3 ปีพวกเขาสามารถจดจำความแตกต่างระหว่าง Set และ Hashmap ได้ แต่พวกเขาไม่รู้วิธีใช้งาน กล่าวอีกนัยหนึ่งผู้เริ่มต้นจดจำลักษณะเฉพาะเท่านั้น แต่เมื่อคุณใช้งานจริงในโครงการคุณต้องตรวจสอบให้แน่ใจว่ามันเป็นจริง เนื่องจากการรับรองนั้นไร้ประโยชน์ฉันสามารถเชื่อในผลลัพธ์เท่านั้น คุณต้องรู้ว่า Hashset สามารถช่วยฉันกำจัดภาระหนักได้อย่างไร ถ้าคุณคิดเกี่ยวกับมันคุณสามารถลบภาระหนักโดยไม่ต้องแฮชเซ็ตได้หรือไม่? วิธีที่ง่ายที่สุดและตรงที่สุดคือการเปรียบเทียบกับข้อมูลประวัติทุกครั้งและแทรกลงในหางของคิวถ้ามันแตกต่างกัน และ Hashset เพียงแค่เร่งกระบวนการนี้
ก่อนอื่นให้ผู้ใช้วัตถุจัดเรียง
@data@builder@allargsconstructorpublic ผู้ใช้ {ID INTEGER ส่วนตัว; ชื่อสตริงส่วนตัว;} รายการ <user> ผู้ใช้ = lists.newarraylist (ผู้ใช้ใหม่ (1, "a"), ผู้ใช้ใหม่ (1, "b"), ผู้ใช้ใหม่ (2, "b"), ผู้ใช้ใหม่ (1, "a");เป้าหมายคือการนำผู้ใช้ออกโดยไม่มี ID ซ้ำกัน เพื่อป้องกันการทะเลาะกันฉันให้กฎ เพียงแค่นำข้อมูลด้วย ID ที่ไม่ซ้ำกันตามต้องการและไม่จำเป็นต้องมีความขยันขันแข็งเกี่ยวกับการคำนวณใดเมื่อ ID เหมือนกัน
ใช้วิธีที่ใช้งานง่ายที่สุด
วิธีนี้คือการใช้รายการว่างเปล่าเพื่อจัดเก็บข้อมูลแบบสำรวจ
@TestPublic เป็นโมฆะ dis1 () {list <ผู้ใช้> result = new LinkedList <> (); สำหรับ (ผู้ใช้ผู้ใช้: ผู้ใช้) {boolean b = result.stream (). anymatch (u -> uTgetId (). เท่ากับ (user.getId ())); if (! b) {result.add (ผู้ใช้); }} system.out.println (ผลลัพธ์);}ใช้ hashset
ทุกคนที่จดจำคุณสมบัติรู้ว่า HashSet สามารถลบน้ำหนักหนักได้ดังนั้นฉันจะลบน้ำหนักหนักได้อย่างไร จดจำลึกลงไปเล็กน้อยและตามวิธีการ HashCode และ Equals แล้วมันขึ้นอยู่กับสองสิ่งนี้ได้อย่างไร? คนที่ยังไม่ได้อ่านซอร์สโค้ดไม่สามารถดำเนินการต่อได้และการสัมภาษณ์จะสิ้นสุดที่นี่
ในความเป็นจริง HashSet ถูกนำมาใช้โดย HASHMAP (ฉันไม่เคยเห็นซอร์สโค้ดและฉันมักจะคิดอย่างสังหรณ์ใจว่ากุญแจของ HASHMAP ถูกนำมาใช้โดย HashSet ซึ่งเป็นสิ่งที่ตรงกันข้าม) ฉันจะไม่ขยายคำอธิบายที่นี่เพียงดูวิธีการก่อสร้างและเพิ่มวิธีการของ Hashset เพื่อทำความเข้าใจ
public hashset () {map = new hashmap <> ();}/*** เห็นได้ชัดว่าถ้ามีอยู่มันจะส่งกลับเท็จถ้าไม่มีอยู่จะส่งคืนจริง*/บูลีนสาธารณะเพิ่ม (e e) {return map.put (e, ปัจจุบัน) == null;}}จากนั้นก็สามารถเห็นได้จากสิ่งนี้ว่าการทำซ้ำของ HashSet นั้นถูกนำมาใช้ตาม HASHMAP และการใช้ HASHMAP นั้นขึ้นอยู่กับวิธีการ HashCode และ Equals อย่างสมบูรณ์ ตอนนี้มันเปิดอย่างสมบูรณ์ หากคุณต้องการใช้ HashSet คุณต้องมองโลกในแง่ดีเกี่ยวกับสองวิธีของคุณ
ในคำถามนี้เราจำเป็นต้องลดลงตาม ID ดังนั้นพื้นฐานการเปรียบเทียบของเราคือ ID การแก้ไขมีดังนี้:
@OverridePublic Boolean เท่ากับ (Object O) {ถ้า (this == o) {return true; } if (o == null || getClass ()! = o.getClass ()) {return false; } ผู้ใช้ user = (ผู้ใช้) o; return objects.equals (id, user.id);}@overridepublic int hashcode () {return objects.hash (id);} // hashCoderesult = 31 * ผลลัพธ์ + (องค์ประกอบ == null? 0: element.hashCode ());ในหมู่พวกเขาวัตถุเรียกอาร์เรย์ 'hashcode และเนื้อหาดังที่แสดงด้านบน คูณด้วย 31 เท่ากับ x << 5-x
การดำเนินการขั้นสุดท้ายมีดังนี้:
@TestPublic เป็นโมฆะ dis2 () {set <user> result = new hashset <> (ผู้ใช้); System.out.println (ผลลัพธ์);}ใช้ Java Stream เพื่อ DEDUPLIPTION
กลับไปที่คำถามเริ่มต้นเหตุผลในการถามคำถามนี้คือถ้าคุณต้องการรับด้านฐานข้อมูลอีกครั้งไปยังฝั่ง Java จำนวนข้อมูลอาจมีขนาดค่อนข้างใหญ่เช่น 100,000 ชิ้น สำหรับข้อมูลขนาดใหญ่การใช้ฟังก์ชั่นที่เกี่ยวข้องกับสตรีมนั้นง่ายที่สุด เช่นเดียวกับสตรีมยังมีฟังก์ชั่นที่แตกต่าง แล้วควรใช้อย่างไร?
ผู้ใช้ PARALLELSTREAM (). แตกต่าง (). foreach (system.out :: println);
ฉันไม่เห็นแลมบ์ดาเป็นพารามิเตอร์นั่นคือไม่มีเงื่อนไขที่กำหนดเอง โชคดีที่ Javadoc ทำเครื่องหมายมาตรฐานการขจัดข้อมูลซ้ำซ้อน:
ส่งคืนสตรีมที่ประกอบด้วยองค์ประกอบที่แตกต่าง (ตาม {@link Object#Equals (Object)}) ของสตรีมนี้เรารู้ว่าเราต้องจดจำหลักการนี้ด้วยเช่นกัน: เมื่อเท่ากับผลตอบแทนที่แท้จริงค่าส่งคืนของ HashCode จะต้องเหมือนกัน นี่เป็นความสับสนเล็กน้อยเมื่อท่องจำ แต่ตราบใดที่เราเข้าใจวิธีการใช้งานของ Hashmap เราจะไม่รู้สึกยากที่จะพูดคุย HashMap ค้นหาเป็นครั้งแรกตามวิธีการ HashCode จากนั้นเปรียบเทียบวิธี Equals
ดังนั้นในการใช้งานที่แตกต่างกันเพื่อให้เกิดการซ้ำซ้อนคุณจะต้องแทนที่วิธี HashCode และ Equals เว้นแต่คุณจะใช้ค่าเริ่มต้น
แล้วทำไมคุณถึงทำเช่นนี้? คลิกในและดูการใช้งาน
<p_in> โหนด <t> ลด (pipelineHelper <t> ตัวช่วย, spliterator <p_in> spliterator) {// ถ้าสตรีมเรียงลำดับแล้วก็ควรสั่งซื้อด้วยเช่นกัน LinkedHashSet :: Add, LinkedHashSet :: Addall); return nodes.node (downop.evaluateparallel (ผู้ช่วย, splitterator));}ภายในถูกนำไปใช้โดยใช้การลด เมื่อคุณนึกถึงการลดลงคุณจะนึกถึงวิธีการใช้งานที่แตกต่างกันทันทีด้วยตัวเอง ฉันแค่ต้องใช้การลดลงและส่วนการคำนวณคือการเปรียบเทียบองค์ประกอบสตรีมกับ hashmap ในตัวให้ข้ามไปถ้ามีและใส่ไว้ในถ้าไม่มี ในความเป็นจริงความคิดเป็นวิธีที่ตรงไปตรงมาที่สุดในตอนแรก
@TestPublic เป็นโมฆะ dis3 () {users.parallelsStream (). ตัวกรอง (distivelbekey (ผู้ใช้ :: getId)). foreach (system.out :: println);} สาธารณะคงที่ <t> predicate <t> dischetbykey (ฟังก์ชั่น <? super t,?> keyextractor) return t -> see.add (keyextractor.apply (t));}แน่นอนถ้ามันเป็นสตรีมแบบขนานสิ่งที่ถ่ายนั้นไม่จำเป็นต้องเป็นคนแรก แต่เป็นการสุ่ม
วิธีการข้างต้นเป็นวิธีที่ดีที่สุดและไม่รุกราน แต่ถ้าคุณต้องใช้ที่แตกต่างกัน คุณสามารถเขียน HashCode และเท่ากับได้เช่นวิธี HashSet เท่านั้น
สรุป
คุณสามารถฝึกฝนได้ว่าคุณสามารถใช้สิ่งเหล่านี้ด้วยตัวเองหรือไม่ มิฉะนั้นมันจะยากที่จะนำพวกเขาออกไปทันทีเมื่อคุณต้องการใช้พวกเขาจริงๆหรือคุณจะเสี่ยง และถ้าคุณต้องการใช้อย่างกล้าหาญมันก็จำเป็นที่จะต้องเข้าใจกฎและหลักการการนำไปปฏิบัติ ตัวอย่างเช่นการใช้งานของ LinkedHashSet และ HashSet แตกต่างกันอย่างไร?
แนบกับซอร์สโค้ด LinkedHashSet แบบง่าย:
คลาสสาธารณะ LinkedHashset <E> ขยาย HashSet <E> อุปกรณ์เสริม <e>, cloneable, java.io.serializable {ส่วนตัวคงที่สุดท้าย Long SerialVersionuid = -2851667679971038690L; Public LinkedHashSet (int initialcapacity, float loadfactor) {super (initialcapacity, loadfactor, true); } Public LinkedHashSet (int initialCapacity) {super (initialCapacity, .75f, true); } สาธารณะ linkedHashSet () {super (16, .75f, true); } Public LinkedHashSet (คอลเลกชัน <? ขยาย e> c) {super (math.max (2*c.size (), 11), .75f, true); Addall (c); } @Override Public Spliterator <E> Spliterator () {return spliterators.spliterator (นี่, Spliterator.distinct | Spliterator.ordered); -เติมเต็ม:
วิธีการลบข้อมูลที่ซ้ำกันออกจากรายการรวบรวมใน Java
1. ลูปองค์ประกอบทั้งหมดในรายการแล้วลบซ้ำ
รายการคงที่สาธารณะ removedUplication (รายการรายการ) {สำหรับ (int i = 0; i <list.size () - 1; i ++) {สำหรับ (int j = list.size () - 1; j> i; j -) {if (list.get (j) .equals (list.get.get.get.get (i)) }}} รายการส่งคืน; - 2. เตะองค์ประกอบที่ซ้ำกันผ่าน HashSet
รายการคงที่สาธารณะ removedUplication (รายการรายการ) {hashset h = new hashset (รายการ); list.clear (); list.addall (h); รายการคืน; -3. ลบองค์ประกอบที่ซ้ำกันใน ArrayList เพื่อรักษาคำสั่งซื้อ
// ลบองค์ประกอบที่ซ้ำกันใน arrayList ให้สั่งซื้อโมฆะคงที่สาธารณะ removedUplicedWithOrder (รายการรายการ) {set set = new HashSet (); แสดงรายการ newlist = new ArrayList (); สำหรับ (iterator iter = list.iterator (); iter.hasnext ();) {implic element = iter.next (); if (set.add (องค์ประกอบ)) newlist.add (องค์ประกอบ); } list.clear (); list.addall (newlist); System.out.println ("ลบรายการซ้ำ" + รายการ); -4. วนซ้ำวัตถุในรายการให้ใช้ list.contain () และหากไม่มีอยู่ให้ใส่ไว้ในคอลเลกชันรายการอื่น
รายการคงที่สาธารณะ removedUplication (รายการรายการ) {list listmp = new ArrayList (); สำหรับ (int i = 0; i <list.size (); i ++) {ถ้า (! listtemp.contains (list.get (i))) {listtemp.add (list.get (i)); }} return listtemp; -