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



sorting (9)

Java8 में एकाधिक फ़ील्ड के साथ छंटनी

package com.java8.chapter1;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import static java.util.Comparator.*;



 public class Example1 {

    public static void main(String[] args) {
        List<Employee> empList = getEmpList();


        // Before Java 8 
        empList.sort(new Comparator<Employee>() {

            @Override
            public int compare(Employee o1, Employee o2) {
                int res = o1.getDesignation().compareTo(o2.getDesignation());
                if (res == 0) {
                    return o1.getSalary() > o2.getSalary() ? 1 : o1.getSalary() < o2.getSalary() ? -1 : 0;
                } else {
                    return res;
                }

            }
        });
        for (Employee emp : empList) {
            System.out.println(emp);
        }
        System.out.println("---------------------------------------------------------------------------");

        // In Java 8

        empList.sort(comparing(Employee::getDesignation).thenComparing(Employee::getSalary));
        empList.stream().forEach(System.out::println);

    }
    private static List<Employee> getEmpList() {
        return Arrays.asList(new Employee("Lakshman A", "Consultent", 450000),
                new Employee("Chaitra S", "Developer", 250000), new Employee("Manoj PVN", "Developer", 250000),
                new Employee("Ramesh R", "Developer", 280000), new Employee("Suresh S", "Developer", 270000),
                new Employee("Jaishree", "Opearations HR", 350000));
    }
}

class Employee {
    private String fullName;
    private String designation;
    private double salary;

    public Employee(String fullName, String designation, double salary) {
        super();
        this.fullName = fullName;
        this.designation = designation;
        this.salary = salary;
    }

    public String getFullName() {
        return fullName;
    }

    public String getDesignation() {
        return designation;
    }

    public double getSalary() {
        return salary;
    }

    @Override
    public String toString() {
        return "Employee [fullName=" + fullName + ", designation=" + designation + ", salary=" + salary + "]";
    }

}

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

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());
      }

});

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

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


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


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

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

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

@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;
}

ऑब्जेक्ट में 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


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

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

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

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));

मैं गुवा की 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();
  }
}

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

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());
    }
}

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

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


यह एक पुराना सवाल है इसलिए मुझे जावा 8 समतुल्य दिखाई नहीं देता है। इस विशिष्ट मामले के लिए यहां एक उदाहरण दिया गया है।

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * Compares multiple parts of the Report object.
 */
public class SimpleJava8ComparatorClass {

    public static void main(String[] args) {
        List<Report> reportList = new ArrayList<>();
        reportList.add(new Report("reportKey2", "studentNumber2", "school1"));
        reportList.add(new Report("reportKey4", "studentNumber4", "school6"));
        reportList.add(new Report("reportKey1", "studentNumber1", "school1"));
        reportList.add(new Report("reportKey3", "studentNumber2", "school4"));
        reportList.add(new Report("reportKey2", "studentNumber2", "school3"));

        System.out.println("pre-sorting");
        System.out.println(reportList);
        System.out.println();

        Collections.sort(reportList, Comparator.comparing(Report::getReportKey)
            .thenComparing(Report::getStudentNumber)
            .thenComparing(Report::getSchool));

        System.out.println("post-sorting");
        System.out.println(reportList);
    }

    private static class Report {

        private String reportKey;
        private String studentNumber;
        private String school;

        public Report(String reportKey, String studentNumber, String school) {
            this.reportKey = reportKey;
            this.studentNumber = studentNumber;
            this.school = school;
        }

        public String getReportKey() {
            return reportKey;
        }

        public void setReportKey(String reportKey) {
            this.reportKey = reportKey;
        }

        public String getStudentNumber() {
            return studentNumber;
        }

        public void setStudentNumber(String studentNumber) {
            this.studentNumber = studentNumber;
        }

        public String getSchool() {
            return school;
        }

        public void setSchool(String school) {
            this.school = school;
        }

        @Override
        public String toString() {
            return "Report{" +
                   "reportKey='" + reportKey + '\'' +
                   ", studentNumber='" + studentNumber + '\'' +
                   ", school='" + school + '\'' +
                   '}';
        }
    }
}

I know this is an old question.

But I just wrote a different kind of solution I want to share.
Using nothing but nested MIN MAX,

It's not fast as it uses 114 of each,
could reduce it to 75 pretty simply like so -> pastebin

But then it's not purely min max anymore.

What might work is doing min/max on multiple integers at once with AVX

PMINSW reference

#include <stdio.h>

static __inline__ int MIN(int a, int b){
int result =a;
__asm__ ("pminsw %1, %0" : "+x" (result) : "x" (b));
return result;
}
static __inline__ int MAX(int a, int b){
int result = a;
__asm__ ("pmaxsw %1, %0" : "+x" (result) : "x" (b));
return result;
}
static __inline__ unsigned long long rdtsc(void){
  unsigned long long int x;
__asm__ volatile (".byte 0x0f, 0x31" :
  "=A" (x));
  return x;
}

#define MIN3(a, b, c) (MIN(MIN(a,b),c))
#define MIN4(a, b, c, d) (MIN(MIN(a,b),MIN(c,d)))

static __inline__ void sort6(int * in) {
  const int A=in[0], B=in[1], C=in[2], D=in[3], E=in[4], F=in[5];

  in[0] = MIN( MIN4(A,B,C,D),MIN(E,F) );

  const int
  AB = MAX(A, B),
  AC = MAX(A, C),
  AD = MAX(A, D),
  AE = MAX(A, E),
  AF = MAX(A, F),
  BC = MAX(B, C),
  BD = MAX(B, D),
  BE = MAX(B, E),
  BF = MAX(B, F),
  CD = MAX(C, D),
  CE = MAX(C, E),
  CF = MAX(C, F),
  DE = MAX(D, E),
  DF = MAX(D, F),
  EF = MAX(E, F);

  in[1] = MIN4 (
  MIN4( AB, AC, AD, AE ),
  MIN4( AF, BC, BD, BE ),
  MIN4( BF, CD, CE, CF ),
  MIN3( DE, DF, EF)
  );

  const int
  ABC = MAX(AB,C),
  ABD = MAX(AB,D),
  ABE = MAX(AB,E),
  ABF = MAX(AB,F),
  ACD = MAX(AC,D),
  ACE = MAX(AC,E),
  ACF = MAX(AC,F),
  ADE = MAX(AD,E),
  ADF = MAX(AD,F),
  AEF = MAX(AE,F),
  BCD = MAX(BC,D),
  BCE = MAX(BC,E),
  BCF = MAX(BC,F),
  BDE = MAX(BD,E),
  BDF = MAX(BD,F),
  BEF = MAX(BE,F),
  CDE = MAX(CD,E),
  CDF = MAX(CD,F),
  CEF = MAX(CE,F),
  DEF = MAX(DE,F);

  in[2] = MIN( MIN4 (
  MIN4( ABC, ABD, ABE, ABF ),
  MIN4( ACD, ACE, ACF, ADE ),
  MIN4( ADF, AEF, BCD, BCE ),
  MIN4( BCF, BDE, BDF, BEF )),
  MIN4( CDE, CDF, CEF, DEF )
  );


  const int
  ABCD = MAX(ABC,D),
  ABCE = MAX(ABC,E),
  ABCF = MAX(ABC,F),
  ABDE = MAX(ABD,E),
  ABDF = MAX(ABD,F),
  ABEF = MAX(ABE,F),
  ACDE = MAX(ACD,E),
  ACDF = MAX(ACD,F),
  ACEF = MAX(ACE,F),
  ADEF = MAX(ADE,F),
  BCDE = MAX(BCD,E),
  BCDF = MAX(BCD,F),
  BCEF = MAX(BCE,F),
  BDEF = MAX(BDE,F),
  CDEF = MAX(CDE,F);

  in[3] = MIN4 (
  MIN4( ABCD, ABCE, ABCF, ABDE ),
  MIN4( ABDF, ABEF, ACDE, ACDF ),
  MIN4( ACEF, ADEF, BCDE, BCDF ),
  MIN3( BCEF, BDEF, CDEF )
  );

  const int
  ABCDE= MAX(ABCD,E),
  ABCDF= MAX(ABCD,F),
  ABCEF= MAX(ABCE,F),
  ABDEF= MAX(ABDE,F),
  ACDEF= MAX(ACDE,F),
  BCDEF= MAX(BCDE,F);

  in[4]= MIN (
  MIN4( ABCDE, ABCDF, ABCEF, ABDEF ),
  MIN ( ACDEF, BCDEF )
  );

  in[5] = MAX(ABCDE,F);
}

int main(int argc, char ** argv) {
  int d[6][6] = {
    {1, 2, 3, 4, 5, 6},
    {6, 5, 4, 3, 2, 1},
    {100, 2, 300, 4, 500, 6},
    {100, 2, 3, 4, 500, 6},
    {1, 200, 3, 4, 5, 600},
    {1, 1, 2, 1, 2, 1}
  };

  unsigned long long cycles = rdtsc();
  for (int i = 0; i < 6; i++) {
    sort6(d[i]);
  }
  cycles = rdtsc() - cycles;
  printf("Time is %d\n", (unsigned)cycles);

  for (int i = 0; i < 6; i++) {
    printf("d%d : %d %d %d %d %d %d\n", i,
     d[i][0], d[i][1], d[i][2],
     d[i][3], d[i][4], d[i][5]);
  }
}

संपादित करें:
Rank order solution inspired by Rex Kerr's, Much faster than the mess above

static void sort6(int *o) {
const int 
A=o[0],B=o[1],C=o[2],D=o[3],E=o[4],F=o[5];
const unsigned char
AB = A>B, AC = A>C, AD = A>D, AE = A>E,
          BC = B>C, BD = B>D, BE = B>E,
                    CD = C>D, CE = C>E,
                              DE = D>E,
a =          AB + AC + AD + AE + (A>F),
b = 1 - AB      + BC + BD + BE + (B>F),
c = 2 - AC - BC      + CD + CE + (C>F),
d = 3 - AD - BD - CD      + DE + (D>F),
e = 4 - AE - BE - CE - DE      + (E>F);
o[a]=A; o[b]=B; o[c]=C; o[d]=D; o[e]=E;
o[15-a-b-c-d-e]=F;
}




java sorting collections