java - कई फ़ील्ड के साथ Collections.sort




sorting (6)

क्या आप कोड के साथ कुछ गलत देखते हैं?

हाँ। आप तुलना करने से पहले तीन फ़ील्ड एक साथ क्यों जोड़ रहे हैं?

मैं शायद ऐसा कुछ करूंगा: (यह मानते हुए कि फ़ील्ड उस क्रम में हैं जिन्हें आप क्रमबद्ध करना चाहते हैं)

@Override 
public int compare(final Report record1, final Report record2) {
    int c;
    c = record1.getReportKey().compareTo(record2.getReportKey());
    if (c == 0)
       c = record1.getStudentNumber().compareTo(record2.getStudentNumber());
    if (c == 0)
       c = record1.getSchool().compareTo(record2.getSchool());
    return c;
}

मेरे पास तीन फ़ील्ड (ऑल स्ट्रिंग टाइप) के साथ "रिपोर्ट" ऑब्जेक्ट्स की एक सूची है -

ReportKey
StudentNumber
School

मेरे पास एक सॉर्ट कोड है जैसे-

Collections.sort(reportList, new Comparator<Report>() {

@Override
public int compare(final Report record1, final Report record2) {
      return (record1.getReportKey() + record1.getStudentNumber() + record1.getSchool())                      
        .compareTo(record2.getReportKey() + record2.getStudentNumber() + record2.getSchool());
      }

});

किसी कारण से, मेरे पास क्रमबद्ध क्रम नहीं है। एक ने खेतों के बीच जगह लगाने की सलाह दी, लेकिन क्यों?

क्या आप कोड के साथ कुछ गलत देखते हैं?


( कई क्षेत्रों के आधार पर जावा में ऑब्जेक्ट्स की सूचियों को सॉर्ट करने के तरीके से )

इस जिस्ट में वर्किंग कोड

गन्दा और शांत: हाथ से छंटनी

Collections.sort(pizzas, new Comparator<Pizza>() {  
    @Override  
    public int compare(Pizza p1, Pizza p2) {  
        int sizeCmp = p1.size.compareTo(p2.size);  
        if (sizeCmp != 0) {  
            return sizeCmp;  
        }  
        int nrOfToppingsCmp = p1.nrOfToppings.compareTo(p2.nrOfToppings);  
        if (nrOfToppingsCmp != 0) {  
            return nrOfToppingsCmp;  
        }  
        return p1.name.compareTo(p2.name);  
    }  
});  

इसके लिए बहुत सारे टाइपिंग, रखरखाव की आवश्यकता होती है और त्रुटि प्रवण होती है।

प्रतिबिंबित तरीका: बीनकंपेटर के साथ छंटनी

ComparatorChain chain = new ComparatorChain(Arrays.asList(
   new BeanComparator("size"), 
   new BeanComparator("nrOfToppings"), 
   new BeanComparator("name")));

Collections.sort(pizzas, chain);  

जाहिर है यह अधिक संक्षेप में है, लेकिन इसके अलावा भी अधिक त्रुटि प्रवण होती है क्योंकि आप इसके बजाय स्ट्रिंग्स का उपयोग करके फ़ील्ड्स का सीधा संदर्भ खो देते हैं (कोई टाइपफैटी, ऑटो-रिफैक्टरिंग नहीं)। अब यदि कोई फ़ील्ड बदल दिया गया है, तो कंपाइलर किसी समस्या की रिपोर्ट भी नहीं करेगा। इसके अलावा, क्योंकि यह समाधान प्रतिबिंब का उपयोग करता है, सॉर्टिंग बहुत धीमी है।

वहां जा रहा है: Google Guava की तुलना के साथ छंटनी

Collections.sort(pizzas, new Comparator<Pizza>() {  
    @Override  
    public int compare(Pizza p1, Pizza p2) {  
        return ComparisonChain.start().compare(p1.size, p2.size).compare(p1.nrOfToppings, p2.nrOfToppings).compare(p1.name, p2.name).result();  
        // or in case the fields can be null:  
        /* 
        return ComparisonChain.start() 
           .compare(p1.size, p2.size, Ordering.natural().nullsLast()) 
           .compare(p1.nrOfToppings, p2.nrOfToppings, Ordering.natural().nullsLast()) 
           .compare(p1.name, p2.name, Ordering.natural().nullsLast()) 
           .result(); 
        */  
    }  
});  

यह बहुत बेहतर है, लेकिन सबसे आम उपयोग मामले के लिए कुछ बॉयलर प्लेट कोड की आवश्यकता है: डिफ़ॉल्ट रूप से शून्य-मानों का मूल्य कम होना चाहिए। शून्य क्षेत्रों के लिए, आपको उस मामले में क्या करना है अमरूद को अतिरिक्त निर्देश देना होगा। यदि आप कुछ विशिष्ट करना चाहते हैं, तो यह एक लचीली तंत्र है, लेकिन अक्सर आप डिफ़ॉल्ट केस (यानी 1, ए, बी, जेड, नल) चाहते हैं।

Apache Commons LikeToBuilder के साथ छंटनी

Collections.sort(pizzas, new Comparator<Pizza>() {  
    @Override  
    public int compare(Pizza p1, Pizza p2) {  
        return new CompareToBuilder().append(p1.size, p2.size).append(p1.nrOfToppings, p2.nrOfToppings).append(p1.name, p2.name).toComparison();  
    }  
});  

गुवा की तुलना चाइना की तरह, यह लाइब्रेरी वर्ग कई क्षेत्रों में आसानी से टाइप करता है, लेकिन शून्य मानों (यानी 1, ए, बी, जेड, नल) के लिए डिफ़ॉल्ट व्यवहार को भी परिभाषित करता है। हालांकि, आप कुछ और निर्दिष्ट नहीं कर सकते हैं, जब तक कि आप अपना स्वयं का तुलनात्मक न दें।

इस प्रकार

आखिरकार यह स्वाद और लचीलापन की आवश्यकता (गुवा की तुलना चेन) बनाम संक्षेप कोड (अपाचे की तुलना टॉबिल्डर) के लिए आता है।

बोनस विधि

मुझे एक अच्छा समाधान मिला जो मल्टीकंपेटर में कोडरव्यूव पर प्राथमिकता के क्रम में एकाधिक तुलनाकर्ताओं को MultiComparator :

class MultiComparator<T> implements Comparator<T> {
    private final List<Comparator<T>> comparators;

    public MultiComparator(List<Comparator<? super T>> comparators) {
        this.comparators = comparators;
    }

    public MultiComparator(Comparator<? super T>... comparators) {
        this(Arrays.asList(comparators));
    }

    public int compare(T o1, T o2) {
        for (Comparator<T> c : comparators) {
            int result = c.compare(o1, o2);
            if (result != 0) {
                return result;
            }
        }
        return 0;
    }

    public static <T> void sort(List<T> list, Comparator<? super T>... comparators) {
        Collections.sort(list, new MultiComparator<T>(comparators));
    }
}

Apcourse Apache Commons संग्रह का पहले से ही इसका उपयोग है:

ComparatorUtils.chainedComparator(comparatorCollection)

Collections.sort(list, ComparatorUtils.chainedComparator(comparators));

ऑब्जेक्ट में 2 फ़ील्ड की तुलना में एक पूर्ण उदाहरण यहां दिया गया है, एक स्ट्रिंग और एक इंट, सॉर्ट करने के लिए कॉललेटर का उपयोग भी कर रहा है।

public class Test {

    public static void main(String[] args) {

        Collator myCollator;
        myCollator = Collator.getInstance(Locale.US);

        List<Item> items = new ArrayList<Item>();

        items.add(new Item("costrels", 1039737, ""));
        items.add(new Item("Costs", 1570019, ""));
        items.add(new Item("costs", 310831, ""));
        items.add(new Item("costs", 310832, ""));

        Collections.sort(items, new Comparator<Item>() {
            @Override
            public int compare(final Item record1, final Item record2) {
                int c;
                //c = record1.item1.compareTo(record2.item1); //optional comparison without Collator                
                c = myCollator.compare(record1.item1, record2.item1);
                if (c == 0) 
                {
                    return record1.item2 < record2.item2 ? -1
                            :  record1.item2 > record2.item2 ? 1
                            : 0;
                }
                return c;
            }
        });     

        for (Item item : items)
        {
            System.out.println(item.item1);
            System.out.println(item.item2);
        }       

    }

    public static class Item
    {
        public String item1;
        public int item2;
        public String item3;

        public Item(String item1, int item2, String item3)
        {
            this.item1 = item1;
            this.item2 = item2;
            this.item3 = item3;
        }       
    }

}

आउटपुट:

costrels 1039737

लागत 310831

लागत 310832

लागत 15700 9 1


मैं गुवा की ComparisonChain का उपयोग कर एक तुलनित्र बनाउंगा :

public class ReportComparator implements Comparator<Report> {
  public int compare(Report r1, Report r2) {
    return ComparisonChain.start()
        .compare(r1.getReportKey(), r2.getReportKey())
        .compare(r1.getStudentNumber(), r2.getStudentNumber())
        .compare(r1.getSchool(), r2.getSchool())
        .result();
  }
}

यदि आप पहले रिपोर्टके के आधार पर सॉर्ट करना चाहते हैं तो छात्र संख्या स्कूल तो स्कूल, आपको उन्हें जोड़ने के बजाए प्रत्येक स्ट्रिंग की तुलना करने की आवश्यकता है। यदि आप रिक्त स्थान के साथ तारों को पैड करते हैं तो आपकी विधि काम कर सकती है ताकि प्रत्येक रिपोर्टकी एक ही लंबाई हो और इसी तरह, लेकिन यह वास्तव में प्रयास के लायक नहीं है। इसके बजाय रिपोर्टकी की तुलना करने के लिए तुलना विधि को बदलें, यदि तुलना करें तो 0 रिटर्न करने के लिए छात्र नम्बर, फिर स्कूल का प्रयास करें।


यदि आप रिपोर्ट कुंजी द्वारा सॉर्ट करना चाहते हैं, तो छात्र संख्या, फिर स्कूल, आपको ऐसा कुछ करना चाहिए:

public class ReportComparator implements Comparator<Report>
{
    public int compare(Report r1, Report r2)
    {
        int result = r1.getReportKey().compareTo(r2.getReportKey());
        if (result != 0)
        {
            return result;
        }
        result = r1.getStudentNumber().compareTo(r2.getStudentNumber());
        if (result != 0)
        {
            return result;
        }
        return r1.getSchool().compareTo(r2.getSchool());
    }
}

यह मानता है कि कोई भी मूल्य शून्य नहीं हो सकता है - बेशक - यदि आपको रिपोर्ट, रिपोर्ट कुंजी, छात्र संख्या या स्कूल के लिए शून्य मानों की अनुमति देने की आवश्यकता होती है तो यह अधिक जटिल हो जाता है।

जबकि आप रिक्त स्थान का उपयोग करके स्ट्रिंग कॉन्सटेनेशन संस्करण को काम करने के लिए प्राप्त कर सकते हैं, फिर भी यह अजीब मामलों में असफल हो जाएगा यदि आपके पास अजीब डेटा था जिसमें स्वयं रिक्त स्थान शामिल थे। उपरोक्त कोड तार्किक कोड है जो आप चाहते हैं ... पहले रिपोर्ट कुंजी से तुलना करें, फिर अगर रिपोर्ट कुंजी एक जैसी हैं तो केवल छात्र संख्या से परेशान करें।







collections