2011-11-07 15 views
47

मैं बतख वस्तुओं का संग्रह मिल गया है और मैं करने के लिए तरह उन्हें एकाधिक कुंजी का उपयोग कर चाहते हैं।छंटाई जावा कई कुंजियों का उपयोग वस्तुओं

class Duck { 
    DuckAge age; //implements Comparable 
    DuckWeight weight; //implements Comparable 
    String name; 
} 
List<Duck> ducks = Pond.getDucks(); 

उदाहरण के लिए। मैं अपनी उम्र द्वारा गौणतः उन्हें उनके वजन द्वारा मुख्य रूप से, और क्रमबद्ध करना चाहते हैं। दो बतख ठीक उसी वजन और ठीक उसी उम्र है, तो चलो एक तृतीयक कुंजी के रूप में उनके नाम का उपयोग उन्हें अलग करते हैं। मैं ऐसा कुछ कर सकता हूं:

Collections.sort(ducks, new Comparator<Duck>(){ 
    @Override 
    public int compare(Duck d1, Duck d2){ 
     int weightCmp = d1.weight.compareTo(d2.weight); 
     if (weightCmp != 0) { 
      return weightCmp; 
     } 
     int ageCmp = d1.age.compareTo(d2.age); 
     if (ageCmp != 0) { 
      return ageCmp; 
     } 
     return d1.name.compareTo(d2.name); 
    } 
}); 

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

संपादित अनावश्यक else शाखाओं

+6

यह बहुत बुरा नहीं लग रहा है, तो आप 'अगर' वापस लौटने के बाद से 'else' दोनों को हटाकर इंडेंटेशन के एक स्तर को हटा सकते हैं, इसलिए इसकी आवश्यकता नहीं है। – stivlo

+14

+1 अपने बतख को क्रम में प्राप्त करने के लिए – Rich

+0

क्या कोर जावा में कोई सुरुचिपूर्ण समाधान नहीं है? – Sid

उत्तर

9

जावा 8 समाधान:

Comparator<Duck> cmp = Comparator.comparing(Duck::getWeight) 
    .thenComparing(Duck::getAge) 
    .thenComparing(Duck::getName); 

lambdas, विधि संदर्भ, और डिफ़ॉल्ट तरीकों के लिए हुर्रे :)!बहुत बुरा हम तो जैसे ही टिककर खेल निर्धारित करें, या स्पष्ट lambdas उपयोग करने के लिए, है:

Comparator<Duck> cmp = Comparator 
    .comparing((Duck duck)-> duck.weight) 
    .thenComparing((Duck duck)-> duck.age) 
    .thenComparing(duck-> duck.name); 

प्रकार अनुमान निहित lambdas साथ काम नहीं करेंगे, तो आप पहले दो lambdas के तर्क के प्रकार का उल्लेख किया है। this answer by Brian Goetz में अधिक जानकारी।

6

हटाया आप Apache Commons Lang से CompareToBuilder उपयोग कर सकते हैं। (यह तुलनीय समझाता है, लेकिन तुलनात्मक के लिए भी काम करता है)।

48

Guava अधिक सुरुचिपूर्ण है:

return ComparisonChain.start() 
    .compare(d1.weight, d2.weight) 
    .compare(d1.age, d2.age) 
    .compare(d1.name, d2.name) 
    .result(); 

अपाचे commons-lang, एक ऐसी ही निर्माण है CompareToBuilder

+1

धन्यवाद, यह वही है जो मैं चाहता था! [गुवा ऑर्डरिंग] (http://google-collections.googlecode.com/svn/trunk/javadoc/index.html?com/google/common/collect/Ordering.html) कक्षा अच्छी तरह से दिखती है, अगर आपके पास पहले से कुछ है तुलनात्मक और उन्हें गठबंधन करना चाहते हैं और सॉर्टिंग के लिए उनका उपयोग करना चाहते हैं। – andras

+3

अपाचे की तुलना टॉबिल्डर एक छोटा और अधिक सुरुचिपूर्ण है, क्योंकि यह पहली बार तुलना की तुलना में डिफ़ॉल्ट रूप से नल को संभालता है। जब तक आप प्रत्येक .compare() कॉल में तीसरा पैरामीटर (ऑर्डरिंग। प्राकृतिक()। NullsFirst()) जोड़ते हैं, तब तक Guava की तुलना Chain एक NullPointerException फेंक देगा। –

+2

यदि, पता है, तो आप नल पसंद करते हैं। –

4

मैं सिर्फ नेस्ट किसी और बयानों के बिना अपने कोड फिर से लिखा है। क्या आपको यह पसंद है?

@Override 
public int compare(Duck d1, Duck d2){ 
    int weightCmp = d1.weight.compareTo(d2.weight); 
    if (weightCmp != 0) { 
     return weightCmp; 
    } 
    int ageCmp = d1.age.compareTo(d2.age); 
    if (ageCmp != 0) { 
     return ageCmp; 
    } 

    return d1.name.compareTo(d2.age); 
} 
+0

हाँ, धन्यवाद, यह बेहतर दिखता है, लेकिन मुख्य समस्या यह थी कि मैं तुलनात्मक रूप से तुलना कर रहा था। अमरूद तुलना चाइना और अपाचे तुलना टॉबिल्डर बेहतर दिखता है। – andras

14

सबसे पहले, अपने समाधान नहीं कि धीमी है।

यदि आप वास्तव में एक और विधि चाहते हैं, तो प्रत्येक बतख को "स्कोर" दें जो अनिवार्य रूप से एक संख्या है जो उनकी तीन विशेषताओं का योग है, लेकिन वजन के लिए भारी भार (लगभग अपरिहार्य पन क्षमा करें) उम्र के लिए कम एक; और नाम के लिए एक बहुत छोटा है।

तुम इतनी प्रत्येक विशेषता के लिए आप रेंज 0..1023 में रहना होगा, प्रत्येक विशेषता के लिए ~ 10 बिट आवंटित कर सकते हैं।

score = ((weight << 10) + age) << 10 + name; 

यह शायद पूरी तरह से अनावश्यक है, लेकिन जो कुछ भी :)

+0

अच्छा थोड़ा चाल, धन्यवाद। मैं सौंदर्य के लिए जा रहा था, प्रदर्शन नहीं, लेकिन मैं इसे ध्यान में रखूंगा :) – andras

20
List<Duck> ducks = new ArrayList<Duck>(); 
Collections.sort(ducks, new Comparator<Duck>() { 

    @Override 
    public int compare(Duck o1, Duck o2) { 

    return new org.apache.commons.lang.builder.CompareToBuilder(). 
     append(o1.weight, o2.weight). 
     append(o1.age, o2.age). 
     append(o1.name, o2.name). 
     toComparison(); 
    } 
}); 
+0

मैं Arraylists को सॉर्ट करने के लिए इसका उपयोग कैसे कर सकता हूं? (एकाधिक कुंजियों का उपयोग करके)? –

+0

क्या आप सरणी (जैसे स्ट्रिंग []) या 'java.util.ArrayList' के बारे में बात कर रहे हैं? यह संग्रहीत तत्वों पर निर्भर करता है। 'Arrays.sort (टी [], तुलनात्मक ) विधि का उपयोग करके सरणी को सॉर्ट किया जा सकता है।' –

+0

मेरा मतलब क्या था, इस प्रकार आपने इस प्रकार के बतख के 2 ऑब्जेक्ट्स को क्रमबद्ध किया है .... "सार्वजनिक int तुलना (बतख ओ 1, बतख ओ 2) "क्या होगा यदि मुझे डक प्रकार की पूरी सरणी सूची को सॉर्ट करना है ... उदाहरण के लिए ArrayList dd = new ArrayList(); ????? –

संबंधित मुद्दे