कैसे कई क्षेत्रों द्वारा वस्तुओं की तुलना करने के लिए


237

मान लें कि आपके पास कुछ ऑब्जेक्ट हैं जिनके पास कई फ़ील्ड हैं जिनकी तुलना उनके द्वारा की जा सकती है:

public class Person {

    private String firstName;
    private String lastName;
    private String age;

    /* Constructors */

    /* Methods */

}

इस उदाहरण में, जब आप पूछें कि क्या:

a.compareTo(b) > 0

आप पूछ रहे हैं कि क्या कोई अंतिम नाम b के पहले आता है, या यदि कोई b से पुराना है, आदि ...

अनावश्यक अव्यवस्था या ओवरहेड को जोड़ने के बिना इस प्रकार की वस्तुओं के बीच कई तुलनाओं को सक्षम करने का सबसे साफ तरीका क्या है?

  • java.lang.Comparable इंटरफ़ेस केवल एक क्षेत्र द्वारा तुलना की अनुमति देता है
  • मेरी तुलना में कई तुलना विधियों (यानी compareByFirstName(), compareByAge()आदि ...) को जोड़ा जाता है।

तो इस बारे में जाने का सबसे अच्छा तरीका क्या है?


3
यह cw क्यों है? यह पूरी तरह से वैध प्रोग्रामिंग प्रश्न है।
एलिी

2
क्या आप जानते हैं कि तुलनीय आप की तरह के रूप में कई क्षेत्रों द्वारा तुलना की अनुमति देता है?
डीजेकाॅलवर्थ

जवाबों:


81

आप Comparatorदो Personवस्तुओं की तुलना करने वाले को लागू कर सकते हैं, और आप जितने चाहें उतने क्षेत्रों की जांच कर सकते हैं। आप अपने तुलनित्र में एक चर में डाल सकते हैं जो यह बताता है कि किस क्षेत्र की तुलना करना है, हालांकि यह संभवत: केवल कई तुलनित्र लिखने के लिए सरल होगा।


5
मैं वास्तव में एक एकल तुलनित्र का उपयोग करने के विचार को पसंद करता हूं। मुझे नहीं लगता कि यह उत्तर गलत है, लेकिन इसे पढ़ने वाले किसी भी व्यक्ति को नीचे दिए गए स्टीव कू उत्तर को अवश्य देखना चाहिए।
फेलिप लेओओ

एकाधिक तुलनित्र केवल तभी थे यदि आप अलग-अलग तुलना विधियां चाहते हैं जो स्वयं डेटा का कार्य नहीं हैं - अर्थात कभी-कभी आप नाम से तुलना करना चाहते हैं, अन्य बार उम्र से, आदि। एक ही समय में कई क्षेत्रों की तुलना करने के लिए, केवल एक तुलनित्र आवश्यक होगा।
ऐली

399

जावा 8 के साथ:

Comparator.comparing((Person p)->p.firstName)
          .thenComparing(p->p.lastName)
          .thenComparingInt(p->p.age);

यदि आपके पास एक्सेसर विधियाँ हैं:

Comparator.comparing(Person::getFirstName)
          .thenComparing(Person::getLastName)
          .thenComparingInt(Person::getAge);

यदि कोई वर्ग तुलनात्मक लागू करता है तो तुलनात्मक विधि में ऐसे तुलनात्मक का उपयोग किया जा सकता है:

@Override
public int compareTo(Person o){
    return Comparator.comparing(Person::getFirstName)
              .thenComparing(Person::getLastName)
              .thenComparingInt(Person::getAge)
              .compare(this, o);
}

5
विशेष रूप से कलाकारों (Person p)को जंजीरों की तुलना के लिए महत्वपूर्ण है।
मेसाउंड

5
बड़ी संख्या में वस्तुओं की तुलना करते समय यह कितना कुशल है, जैसे छँटाई करते समय? क्या इसे Comparatorहर कॉल में नए उदाहरण बनाने होंगे ?
jjurm

4
मुझे एक NullPointerException मिलती है जब मैं जिन फील्ड्स की तुलना कर रहा हूं उनमें से एक स्ट्रिंग की तरह अशक्त है। क्या इस तुलना प्रारूप को बनाए रखने के लिए कुछ भी है लेकिन इसे शून्य सुरक्षित रखने की अनुमति है?
'21

3
@jjurm .thenComparing(Person::getLastName, Comparator.nullsFirst(Comparator.naturalOrder()))- पहले क्षेत्र चयनकर्ता, फिर तुलनित्र
गवेंको

2
@jjurm जब आप इसे compareToऊपर दिखाए गए तरीके से उपयोग करते हैं तो Comparatorहर बार विधि को कहा जाता है। आप एक निजी स्थिर अंतिम क्षेत्र में तुलनित्र को संग्रहीत करके इसे रोक सकते हैं।
गैंडाल्फ

165

आपको लागू करना चाहिए Comparable <Person>। यह मानते हुए कि सभी क्षेत्र शून्य नहीं होंगे (सादगी के लिए), यह आयु एक अंतर है, और रैंकिंग की तुलना पहले, अंतिम, आयु से की जाती है, compareToविधि काफी सरल है:

public int compareTo(Person other) {
    int i = firstName.compareTo(other.firstName);
    if (i != 0) return i;

    i = lastName.compareTo(other.lastName);
    if (i != 0) return i;

    return Integer.compare(age, other.age);
}

10
यदि आप तुलना योग्य <व्यक्ति> को लागू करते हैं, तो विधि तुलना (व्यक्ति पी) है .. ऐसा लगता है कि यह उत्तर तुलनाकर्ता के तुलना <टी o1, टी o2> विधि के साथ मिलाया गया था
माइक

5
यह अनुशंसित नहीं है। जब आपके पास कई फ़ील्ड हों, तो तुलनित्र का उपयोग करें।
इंडिका

1
इस समय इसका सबसे अच्छा समाधान है, (तुलनाकर्ताओं से बेहतर)
वासिल सुड्डू

4
@indika, मैं उत्सुक हूं: यह अनुशंसित क्यों नहीं है? एक से अधिक संपत्तियों का उपयोग करने की तुलना करना मुझे पूरी तरह से ठीक लगता है।
ars-longa-vita-brevis

4
@ ars-longa-vita-brevis, यदि आप तुलनीय का उपयोग कर रहे हैं तो सॉर्टिंग लॉजिक उसी वर्ग में होना चाहिए जिसकी वस्तुओं को छांटा जा रहा है इसलिए इसे वस्तुओं का प्राकृतिक क्रम कहा जाता है। तुलनित्र के उपयोग से आप व्यक्ति वर्ग के बाहर कस्टम छँटाई तर्क लिख सकते हैं। यदि आप केवल अपने पहले नाम या अंतिम नाम से व्यक्ति की वस्तुओं की तुलना करना चाहते हैं, तो आप इस तर्क का उपयोग नहीं कर सकते। आपको इसे फिर से लिखना होगा,
indika

78

( कई क्षेत्रों के आधार पर जावा में वस्तुओं की सूची को छाँटने के तरीके से )

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

जावा 8 लैम्ब्डा का उपयोग करना (10 अप्रैल 2019 को जोड़ा गया)

जावा 8 ने लैंबडा (भले ही अमरूद और अपाचे कॉमन्स अभी भी अधिक लचीलेपन की पेशकश कर सकते हैं) द्वारा इसे अच्छी तरह से हल करता है:

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

नीचे @ gaoagong के उत्तर के लिए धन्यवाद

गन्दा और दृढ़: हाथ से छँटाई

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 अमरूद की तुलना के साथ छंटनी

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 तुलना के साथ छंटनी

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, ए, बी, जेड, नल)। हालाँकि, आप कुछ भी निर्दिष्ट नहीं कर सकते, जब तक कि आप अपने स्वयं के तुलनित्र प्रदान न करें।

इस प्रकार

अंततः यह स्वाद और लचीलेपन की आवश्यकता के लिए नीचे आता है (अमरूद की तुलना) बनाम संक्षिप्त कोड (Apache's ComparToBuilder)।

बोनस विधि

मुझे एक अच्छा समाधान मिला जो कोडरव्यू पर प्राथमिकता में क्रम में कई तुलनाकर्ताओं को जोड़ता है 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));
    }
}

ऑफ़कोर्स अपाचे कॉमन्स कलेक्शंस का उपयोग इसके लिए पहले से ही है:

ComparatorUtils.chainedComparator (comparatorCollection)

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

22

@Patrick करने के लिए तरह एक से अधिक क्षेत्र लगातार कोशिश ComparatorChain

एक तुलनित्र एक तुलनित्र है जो अनुक्रम में एक या एक से अधिक तुलनाकर्ताओं को लपेटता है। तुलनित्रचेकिन प्रत्येक तुलनाकर्ता को अनुक्रम में 1 तक पुकारता है) कोई भी एकल तुलनित्र एक शून्य-शून्य परिणाम देता है (और फिर वह परिणाम वापस आ जाता है), या 2) तुलनित्रकोण समाप्त हो जाता है (और शून्य वापस आ जाता है)। इस प्रकार की छंटनी SQL में बहु-स्तंभ छँटाई के समान है, और यह वर्ग जावा वर्गों को सूची को क्रमबद्ध करते समय उस तरह के व्यवहार का अनुकरण करने की अनुमति देता है।

SQL- जैसे सॉर्टिंग को और अधिक सुविधाजनक बनाने के लिए, सूची में किसी भी तुलनाकर्ता का क्रम उलट सकता है।

एक ऐसी विधि को कॉल करना जो नए कंप्रेशर्स को जोड़ता है या तुलना (ऑब्जेक्ट, ऑब्जेक्ट) के बाद आरोही / अवरोही प्रकार को परिवर्तित करता है, जिसे UnsupportedOperationException में परिणामित किया जाएगा। हालांकि, तुलनाकर्ताओं की अंतर्निहित सूची या सॉर्ट क्रम को परिभाषित करने वाले बिटसेट को न बदलने का ध्यान रखें।

तुलनित्र के उदाहरण सिंक्रनाइज़ नहीं हैं। निर्माण के समय वर्ग थ्रेड-सुरक्षित नहीं है, लेकिन सभी सेटअप संचालन पूर्ण होने के बाद कई तुलनाओं को करने के लिए थ्रेड-सुरक्षित है।


20

एक अन्य विकल्प जिस पर आप हमेशा विचार कर सकते हैं वह है अपाचे कॉमन्स। यह बहुत सारे विकल्प प्रदान करता है।

import org.apache.commons.lang3.builder.CompareToBuilder;

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

public int compare(Person a, Person b){

   return new CompareToBuilder()
     .append(a.getName(), b.getName())
     .append(a.getAddress(), b.getAddress())
     .toComparison();
}


10
import com.google.common.collect.ComparisonChain;

/**
 * @author radler
 * Class Description ...
 */
public class Attribute implements Comparable<Attribute> {

    private String type;
    private String value;

    public String getType() { return type; }
    public void setType(String type) { this.type = type; }

    public String getValue() { return value; }
    public void setValue(String value) { this.value = value; }

    @Override
    public String toString() {
        return "Attribute [type=" + type + ", value=" + value + "]";
    }

    @Override
    public int compareTo(Attribute that) {
        return ComparisonChain.start()
            .compare(this.type, that.type)
            .compare(this.value, that.value)
            .result();
    }

}

1
मुझे यह रणनीति बहुत पसंद है। धन्यवाद!
श्री पॉलीविरल

सबसे प्रभावी तरीका! धन्यवाद
ज़कारिया Bouazza

8

जावा 8 स्ट्रीमिंग एपीआई का उपयोग करने में सक्षम लोगों के लिए, यहां एक अच्छी तरह से प्रलेखित neater दृष्टिकोण है: लैम्ब्डा और सॉर्टिंग

मुझे C # LINQ के बराबर की तलाश थी:

.ThenBy(...)

मैं तुलनित्र पर जावा 8 में तंत्र पाया:

.thenComparing(...)

तो यहाँ स्निपेट है जो एल्गोरिथ्म को प्रदर्शित करता है।

    Comparator<Person> comparator = Comparator.comparing(person -> person.name);
    comparator = comparator.thenComparing(Comparator.comparing(person -> person.age));

एक neater तरीके के लिए ऊपर दिए गए लिंक की जाँच करें और यह समझें कि कैसे Java के प्रकार के निष्कर्ष यह LINQ की तुलना में परिभाषित करने के लिए थोड़ा और अधिक क्लिंकी है।

यहाँ संदर्भ के लिए पूर्ण इकाई परीक्षण है:

@Test
public void testChainedSorting()
{
    // Create the collection of people:
    ArrayList<Person> people = new ArrayList<>();
    people.add(new Person("Dan", 4));
    people.add(new Person("Andi", 2));
    people.add(new Person("Bob", 42));
    people.add(new Person("Debby", 3));
    people.add(new Person("Bob", 72));
    people.add(new Person("Barry", 20));
    people.add(new Person("Cathy", 40));
    people.add(new Person("Bob", 40));
    people.add(new Person("Barry", 50));

    // Define chained comparators:
    // Great article explaining this and how to make it even neater:
    // http://blog.jooq.org/2014/01/31/java-8-friday-goodies-lambdas-and-sorting/
    Comparator<Person> comparator = Comparator.comparing(person -> person.name);
    comparator = comparator.thenComparing(Comparator.comparing(person -> person.age));

    // Sort the stream:
    Stream<Person> personStream = people.stream().sorted(comparator);

    // Make sure that the output is as expected:
    List<Person> sortedPeople = personStream.collect(Collectors.toList());
    Assert.assertEquals("Andi",  sortedPeople.get(0).name); Assert.assertEquals(2,  sortedPeople.get(0).age);
    Assert.assertEquals("Barry", sortedPeople.get(1).name); Assert.assertEquals(20, sortedPeople.get(1).age);
    Assert.assertEquals("Barry", sortedPeople.get(2).name); Assert.assertEquals(50, sortedPeople.get(2).age);
    Assert.assertEquals("Bob",   sortedPeople.get(3).name); Assert.assertEquals(40, sortedPeople.get(3).age);
    Assert.assertEquals("Bob",   sortedPeople.get(4).name); Assert.assertEquals(42, sortedPeople.get(4).age);
    Assert.assertEquals("Bob",   sortedPeople.get(5).name); Assert.assertEquals(72, sortedPeople.get(5).age);
    Assert.assertEquals("Cathy", sortedPeople.get(6).name); Assert.assertEquals(40, sortedPeople.get(6).age);
    Assert.assertEquals("Dan",   sortedPeople.get(7).name); Assert.assertEquals(4,  sortedPeople.get(7).age);
    Assert.assertEquals("Debby", sortedPeople.get(8).name); Assert.assertEquals(3,  sortedPeople.get(8).age);
    // Andi     : 2
    // Barry    : 20
    // Barry    : 50
    // Bob      : 40
    // Bob      : 42
    // Bob      : 72
    // Cathy    : 40
    // Dan      : 4
    // Debby    : 3
}

/**
 * A person in our system.
 */
public static class Person
{
    /**
     * Creates a new person.
     * @param name The name of the person.
     * @param age The age of the person.
     */
    public Person(String name, int age)
    {
        this.age = age;
        this.name = name;
    }

    /**
     * The name of the person.
     */
    public String name;

    /**
     * The age of the person.
     */
    public int age;

    @Override
    public String toString()
    {
        if (name == null) return super.toString();
        else return String.format("%s : %d", this.name, this.age);
    }
}

7

Comparatorइस तरह के उपयोग के मामले के लिए मैन्युअल रूप से लिखना एक भयानक समाधान आईएमओ है। इस तरह के तदर्थ दृष्टिकोण में कई कमियां हैं:

  • कोई कोड पुन: उपयोग। DRY का उल्लंघन करता है।
  • बॉयलरप्लेट।
  • त्रुटियों की संभावना बढ़ जाती है।

तो उपाय क्या है?

पहले कुछ सिद्धांत।

आइए हम प्रस्ताव को " Aतुलना का समर्थन करता है" प्रकार को निरूपित करते हैं Ord A। (कार्यक्रम के दृष्टिकोण से, आप Ord Aदो Aएस की तुलना के लिए तर्क युक्त एक वस्तु के रूप में सोच सकते हैं । हां, बस की तरह Comparator।)

अब, यदि Ord Aऔर Ord Bफिर, उनके सम्मिश्र (A, B)को भी तुलना का समर्थन करना चाहिए। यानी Ord (A, B)। यदि Ord A, Ord Bऔर Ord C, तब Ord (A, B, C)

हम इस तर्क को मनमाने ढंग से बढ़ा सकते हैं, और कह सकते हैं:

Ord A, Ord B, Ord C, ..., Ord ZOrd (A, B, C, .., Z)

चलिए इस कथन को 1 कहते हैं।

कंपोजिट की तुलना आपके प्रश्न में वर्णित के अनुसार ही काम करेगी: पहली तुलना पहले करने की कोशिश की जाएगी, उसके बाद अगला, फिर अगला, और इसी तरह।

यह हमारे समाधान का पहला हिस्सा है। अब दूसरा भाग।

आप जानते हैं Ord A, और बदलने के लिए कैसे पता Bकरने के लिए A(जो परिवर्तन समारोह कॉल f), तो आप भी कर सकते हैं Ord B। कैसे? खैर, जब दो Bउदाहरणों की तुलना की जानी है, तो आप पहले उन्हें Aउपयोग करने के लिए बदल देते हैं fऔर फिर लागू करते हैं Ord A

यहां, हम परिवर्तन B → Aका मानचित्रण कर रहे हैं Ord A → Ord B। इसे कॉन्ट्रैवियरी मैपिंग (या comapशॉर्ट के लिए) के रूप में जाना जाता है ।

Ord A, (B → A)कॉमप Ord B

चलिए इस कथन को २।


अब इसे अपने उदाहरण पर लागू करते हैं।

आपके पास एक डेटा प्रकार Personहै, जिसमें तीन प्रकार के फ़ील्ड शामिल हैं String

  • हम यह जानते हैं Ord String। द्वारा बयान 1, Ord (String, String, String)

  • हम आसानी से से एक समारोह में लिख सकते हैं Personकरने के लिए (String, String, String)। (बस तीन फ़ील्ड लौटाएँ।) चूंकि हम जानते हैं Ord (String, String, String)और Person → (String, String, String), कथन 2 के द्वारा, हम comapप्राप्त करने के लिए उपयोग कर सकते हैं Ord Person

QED।


मैं इन सभी अवधारणाओं को कैसे लागू करूं?

अच्छी खबर यह है कि आपके पास नहीं है। पहले से ही एक पुस्तकालय मौजूद है जो इस पोस्ट में वर्णित सभी विचारों को लागू करता है। (यदि आप उत्सुक हैं कि इन्हें कैसे लागू किया जाता है, तो आप हुड के नीचे देख सकते हैं ।)

इस तरह से कोड इसके साथ दिखेगा:

Ord<Person> personOrd = 
 p3Ord(stringOrd, stringOrd, stringOrd).comap(
   new F<Person, P3<String, String, String>>() {
     public P3<String, String, String> f(Person x) {
       return p(x.getFirstName(), x.getLastname(), x.getAge());
     }
   }
 );

स्पष्टीकरण:

  • stringOrdएक प्रकार की वस्तु है Ord<String>। यह हमारे मूल "तुलना का समर्थन करता है" प्रस्ताव से मेल खाती है।
  • p3Ordएक विधि है कि लेता है Ord<A>, Ord<B>, Ord<C>, और रिटर्न Ord<P3<A, B, C>>। यह कथन 1. से मेल खाता है ( P3तीन तत्वों वाले उत्पाद के लिए है। उत्पाद कंपोजिट के लिए बीजगणितीय शब्द है।)
  • comapअच्छी तरह से मेल खाती है comap,।
  • F<A, B>एक परिवर्तन समारोह का प्रतिनिधित्व करता है A → B
  • p उत्पादों को बनाने के लिए एक कारखाना विधि है।
  • संपूर्ण अभिव्यक्ति कथन 2 से मेल खाती है।

उम्मीद है की वो मदद करदे।


5

तुलना के तरीकों के बजाय आप बस व्यक्ति वर्ग के अंदर कई प्रकार के "तुलनित्र" उपवर्गों को परिभाषित करना चाह सकते हैं। इस तरह से आप उन्हें मानक संग्रह सॉर्टिंग विधियों में पास कर सकते हैं।


3

मुझे लगता है कि अगर आपकी तुलना एल्गोरिथ्म "चतुर" थी तो यह और अधिक भ्रामक होगा। मैं आपके द्वारा सुझाई गई कई तुलना विधियों के साथ जाऊँगा।

मेरे लिए एकमात्र अपवाद समानता होगी। यूनिट टेस्टिंग के लिए, यह ओवरराइड करने के लिए मेरे लिए उपयोगी है। यह निर्धारित करने के लिए कि कई फ़ील्ड दो ऑब्जेक्ट्स के बीच समान हैं (और नहीं कि संदर्भ बराबर हैं)।


3

यदि कोई व्यक्ति किसी व्यक्ति को आदेश दे सकता है, तो कई तरीके हैं, आप कहीं भी स्थिरांक के रूप में कई तुलनित्र सेटअप कर सकते हैं । अधिकांश सॉर्ट संचालन और सॉर्ट किए गए संग्रह एक पैरामीटर के रूप में एक तुलनित्र लेते हैं।


3
//Following is the example in jdk 1.8
package com;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

class User {
    private String firstName;
    private String lastName;
    private Integer age;

    public Integer getAge() {
        return age;
    }

    public User setAge(Integer age) {
        this.age = age;
        return this;
    }

    public String getFirstName() {
        return firstName;
    }

    public User setFirstName(String firstName) {
        this.firstName = firstName;
        return this;
    }

    public String getLastName() {
        return lastName;
    }

    public User setLastName(String lastName) {
        this.lastName = lastName;
        return this;
    }

}

public class MultiFieldsComparision {

    public static void main(String[] args) {
        List<User> users = new ArrayList<User>();

        User u1 = new User().setFirstName("Pawan").setLastName("Singh").setAge(38);
        User u2 = new User().setFirstName("Pawan").setLastName("Payal").setAge(37);
        User u3 = new User().setFirstName("Anuj").setLastName("Kumar").setAge(60);
        User u4 = new User().setFirstName("Anuj").setLastName("Kumar").setAge(43);
        User u5 = new User().setFirstName("Pawan").setLastName("Chamoli").setAge(44);
        User u6 = new User().setFirstName("Pawan").setLastName("Singh").setAge(5);

        users.add(u1);
        users.add(u2);
        users.add(u3);
        users.add(u4);
        users.add(u5);
        users.add(u6);

        System.out.println("****** Before Sorting ******");

        users.forEach(user -> {
            System.out.println(user.getFirstName() + " , " + user.getLastName() + " , " + user.getAge());
        });

        System.out.println("****** Aftre Sorting ******");

        users.sort(
                Comparator.comparing(User::getFirstName).thenComparing(User::getLastName).thenComparing(User::getAge));

        users.forEach(user -> {
            System.out.println(user.getFirstName() + " , " + user.getLastName() + " , " + user.getAge());
        });

    }

}

3

यदि हमें कई क्षेत्रों के आधार पर व्यक्ति वस्तु को क्रमबद्ध करना है तो उसी का कोड कार्यान्वयन यहाँ है।

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

public class Person {

private String firstName;
private String lastName;
private int age;

public String getFirstName() {
    return firstName;
}

public void setFirstName(String firstName) {
    this.firstName = firstName;
}

public String getLastName() {
    return lastName;
}

public void setLastName(String lastName) {
    this.lastName = lastName;
}

public int getAge() {
    return age;
}

public void setAge(int age) {
    this.age = age;
}

public Person(String firstName, String lastName, int age) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
}


static class PersonSortingComparator implements Comparator<Person> {

    @Override
    public int compare(Person person1, Person person2) {

        // for first name comparison
        int firstNameCompare = person1.getFirstName().compareTo(person2.getFirstName());

        // for last name comparison
        int lastNameCompare = person1.getLastName().compareTo(person2.getLastName());

        // for last name comparison
        int ageCompare = person1.getAge() - person2.getAge();

        // Now comparing
        if (firstNameCompare == 0) {
            if (lastNameCompare == 0) {
                return ageCompare;
            }
            return lastNameCompare;
        }
        return firstNameCompare;
    }
}

public static void main(String[] args) {
    Person person1 = new Person("Ajay", "Kumar", 27);
    Person person2 = new Person("Ajay","Gupta", 23);
    Person person3 = new Person("Ajay","Kumar", 22);


    ArrayList<Person> persons = new ArrayList<>();
    persons.add(person1);
    persons.add(person2);
    persons.add(person3);


    System.out.println("Before Sorting:\n");
    for (Person person : persons) {
        System.out.println(person.firstName + " " + person.lastName + " " + person.age);
    }

    Collections.sort(persons, new PersonSortingComparator());

    System.out.println("After Sorting:\n");
    for (Person person : persons) {
        System.out.println(person.firstName + " " + person.lastName + " " + person.age);
    }
}

}

2
//here threshold,buyRange,targetPercentage are three keys on that i have sorted my arraylist 
final Comparator<BasicDBObject> 

    sortOrder = new Comparator<BasicDBObject>() {
                    public int compare(BasicDBObject e1, BasicDBObject e2) {
                        int threshold = new Double(e1.getDouble("threshold"))
                        .compareTo(new Double(e2.getDouble("threshold")));
                        if (threshold != 0)
                            return threshold;

                        int buyRange = new Double(e1.getDouble("buyRange"))
                        .compareTo(new Double(e2.getDouble("buyRange")));
                        if (buyRange != 0)
                            return buyRange;

                        return (new Double(e1.getDouble("targetPercentage")) < new Double(
                                e2.getDouble("targetPercentage")) ? -1 : (new Double(
                                        e1.getDouble("targetPercentage")) == new Double(
                                                e2.getDouble("targetPercentage")) ? 0 : 1));
                    }
                };
                Collections.sort(objectList, sortOrder);

मैं इस सवाल पर आया क्योंकि मेरा कोड आपके जवाब को पसंद करने लगा था;)
जान ग्रथ

0

यदि आप तुलनात्मक इंटरफ़ेस लागू करते हैं , तो आप ऑर्डर करने के लिए एक साधारण संपत्ति चुनना चाहेंगे। इसे प्राकृतिक ऑर्डरिंग के रूप में जाना जाता है। इसे डिफ़ॉल्ट मानें। इसका उपयोग हमेशा किया जाता है जब कोई विशिष्ट तुलनित्र की आपूर्ति नहीं की जाती है। आमतौर पर यह नाम है, लेकिन आपका उपयोग मामला कुछ अलग करने के लिए कह सकता है। आप किसी भी संख्या का उपयोग करने के लिए स्वतंत्र हैं तुलनात्मक आदेश को ओवरराइड करने के लिए आप विभिन्न संग्रह एपीआई को आपूर्ति कर सकते हैं।

यह भी ध्यान दें कि आम तौर पर अगर a.compareTo (b) == 0 है, तो a.equals (b) == सच है। यह ठीक है अगर नहीं, लेकिन इसके बारे में जागरूक होने के साइड इफेक्ट्स हैं। तुलनात्मक इंटरफ़ेस पर उत्कृष्ट javadocs देखें और आपको इस पर बहुत सारी शानदार जानकारी मिलेगी।


0

निम्नलिखित ब्लॉग अच्छा जंजीर तुलनित्र उदाहरण दिया

http://www.codejava.net/java-core/collections/sorting-a-list-by-multiple-attributes-example

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

/**
 * This is a chained comparator that is used to sort a list by multiple
 * attributes by chaining a sequence of comparators of individual fields
 * together.
 *
 */
public class EmployeeChainedComparator implements Comparator<Employee> {

    private List<Comparator<Employee>> listComparators;

    @SafeVarargs
    public EmployeeChainedComparator(Comparator<Employee>... comparators) {
        this.listComparators = Arrays.asList(comparators);
    }

    @Override
    public int compare(Employee emp1, Employee emp2) {
        for (Comparator<Employee> comparator : listComparators) {
            int result = comparator.compare(emp1, emp2);
            if (result != 0) {
                return result;
            }
        }
        return 0;
    }
}

तुलनित्र कॉलिंग:

Collections.sort(listEmployees, new EmployeeChainedComparator(
                new EmployeeJobTitleComparator(),
                new EmployeeAgeComparator(),
                new EmployeeSalaryComparator())
        );


0

जावा में हैशकोड विधि के साथ दो वस्तुओं की तुलना करना आसान है

public class Sample{

  String a=null;
  String b=null;

  public Sample(){
      a="s";
      b="a";
  }
  public Sample(String a,String b){
      this.a=a;
      this.b=b;
  }
  public static void main(String args[]){
      Sample f=new Sample("b","12");
      Sample s=new Sample("b","12");
      //will return true
      System.out.println((s.a.hashCode()+s.b.hashCode())==(f.a.hashCode()+f.b.hashCode()));

      //will return false
      Sample f=new Sample("b","12");
      Sample s=new Sample("b","13");
      System.out.println((s.a.hashCode()+s.b.hashCode())==(f.a.hashCode()+f.b.hashCode()));

}

कृपया ऐसा मत करो। हैशकोड का उपयोग समानता तुलना के लिए नहीं बल्कि हैशटेबल इंडेक्सिंग के लिए किया जाना चाहिए। हैश टकराव के परिणामस्वरूप दो अलग-अलग वस्तुओं के लिए समानता हो सकती है। यहां तक ​​कि हैशटैले होने पर भी हैशटेब वास्तविक समानता पर भरोसा करते हैं।
नोएल विडमर

0

आमतौर पर मैं अपनी compareTo()पद्धति को इस तरह से ओवरराइड करता हूं जब भी मुझे मल्टीलेवल छंटाई करनी होती है।

public int compareTo(Song o) {
    // TODO Auto-generated method stub
    int comp1 = 10000000*(movie.compareTo(o.movie))+1000*(artist.compareTo(o.artist))+songLength;
    int comp2 = 10000000*(o.movie.compareTo(movie))+1000*(o.artist.compareTo(artist))+o.songLength;
    return comp1-comp2;
} 

यहाँ पहली वरीयता फिल्म के नाम को दी जाती है फिर कलाकार को और अंतिम रूप से सॉन्ग लैंथ को। आपको बस यह सुनिश्चित करना है कि उन गुणक एक दूसरे की सीमाओं को पार न करने के लिए पर्याप्त दूर हैं।


-2

Google की अमरूद लाइब्रेरी का उपयोग करना आसान है ।

जैसे Objects.equal(name, name2) && Objects.equal(age, age2) && ...

और ज्यादा उदाहरण:


समानता की जाँच करने से अलग चीजों की तुलना करना
क्लिंट ईस्टवुड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.