2015-06-16 41 views
19

में ऑब्जेक्ट्स की दो सूची विलय करना मेरे पास 20 गुण (attrib1, attrib2 .. attrib20) और इसके संबंधित गेटर्स और सेटर्स के साथ जावा क्लास Parent है। इसके अलावा मेरे पास Parent ऑब्जेक्ट्स की दो सूचियां हैं: list1 और list2जावा 8

अब मैं दोनों सूचियों को मर्ज करना चाहता हूं और attrib1 और attrib2 पर आधारित डुप्लिकेट ऑब्जेक्ट्स से बचना चाहता हूं।

जावा 8 का उपयोग करना:

List<Parent> result = Stream.concat(list1.stream(), list2.stream()) 
       .distinct() 
       .collect(Collectors.toList()); 

लेकिन जो जगह में मैं गुण निर्दिष्ट करने के लिए है? क्या मुझे hashCode और equals विधि ओवरराइड करना चाहिए?

+0

डुप्लिकेट मानों से बचने के लिए सेट का उपयोग करें। – Noundla

+1

देखें http://stackoverflow.com/questions/27870136/java-lambda-stream-distinct-on-arbitrary-key/27872086 –

+1

कूल इको सुविधा जो आपको मिली है :) – CKing

उत्तर

14

आप equals और hashCode, यह वर्ग Parent के अंदर है क्या करने के लिए जगह लागू करना चाहते हैं। आप इस किया था, तो उस वर्ग के भीतर की तरह

@Override 
    public int hashCode() { 
     return Objects.hash(getAttrib1(), getAttrib2(), getAttrib3(), 
      // … 
          getAttrib19(), getAttrib20()); 
    } 

    @Override 
    public boolean equals(Object obj) { 
     if(this==obj) return true; 
     if(!(obj instanceof Parent)) return false; 
     Parent p=(Parent) obj; 
     return Objects.equals(getAttrib1(), p.getAttrib1()) 
      && Objects.equals(getAttrib2(), p.getAttrib2()) 
      && Objects.equals(getAttrib3(), p.getAttrib3()) 
      // … 
      && Objects.equals(getAttrib19(), p.getAttrib19()) 
      && Objects.equals(getAttrib20(), p.getAttrib20()); 
    } 

विधियों को जोड़ने, distinct() एक Stream<Parent> पर लागू स्वचालित रूप से सही काम करेंगे।


यदि आप नहीं करना चाहते हैं (या नहीं कर सकते हैं) वर्ग Parent बदलने के लिए, वहाँ समानता के लिए कोई प्रतिनिधिमंडल तंत्र है, लेकिन आप आदेश देने के रूप में एक प्रतिनिधिमंडल तंत्र है का सहारा हो सकता है:

Comparator<Parent> c=Comparator.comparing(Parent::getAttrib1) 
     .thenComparing(Parent::getAttrib2) 
     .thenComparing(Parent::getAttrib3) 
     // … 
     .thenComparing(Parent::getAttrib19) 
     .thenComparing(Parent::getAttrib20); 

यह गुणों के आधार पर एक आदेश परिभाषित करता है। यह आवश्यक है कि गुणों के प्रकार तुलनीय हैं। आप इस तरह के एक परिभाषा है, तो आप एक distinct() के बराबर, के आधार पर लागू करने के लिए उपयोग कर सकते हैं कि Comparator:

List<Parent> result = Stream.concat(list1.stream(), list2.stream()) 
     .filter(new TreeSet<>(c)::add) 
     .collect(Collectors.toList()); 

वहाँ भी एक धागा सुरक्षित संस्करण मामले में, है आप समानांतर धाराओं के साथ उपयोग करना चाहते हैं :

List<Parent> result = Stream.concat(list1.stream(), list2.stream()) 
     .filter(new ConcurrentSkipListSet<>(c)::add) 
     .collect(Collectors.toList()); 
0

सूचियों से डुप्लिकेट से बचने के लिए Parent कक्षा में equals और hashCode विधियों को ओवरराइड करें। यह आपको सटीक परिणाम देगा जो आप चाहते हैं।

+4

यह बुरी सलाह है। 'हैशकोड' को ओवरराइड किए बिना 'बराबर' ओवरराइड न करें। – Marvin

+0

http://stackoverflow.com/questions/2265503/why-do-i-need-to-override-the-equals-and-hashcode-methods-in-java बस इसे पढ़ें और पता चलेगा क्यों, धन्यवाद :) –

0

यदि आप .equals(…) और .hashCode() ओवरराइड करना चाहते हैं, तो आपको Parent कक्षा पर ऐसा करने की आवश्यकता है। ध्यान दें कि इससे असफल होने के लिए Parent के अन्य उपयोग हो सकते हैं। एलेक्सिस सी का जुड़ाव समाधान अधिक रूढ़िवादी है।

0

उदाहरण के लिए:

public class Parent { 

    public int no; 
    public String name; 

    @Override 
    public int hashCode() { 
     return (no << 4)^name.hashCode(); 
    } 

    @Override 
    public boolean equals(Object obj) { 
     if (!(obj instanceof Parent)) 
      return false; 
     Parent o = (Parent)obj; 
     return this.no == o.no && this.name.equals(o.name); 
    } 
}