2017-10-24 11 views
19

Comparator मैंने अपने TreeMap में उपयोग किए गए व्यवहार को तोड़ दिया जिसका इरादा उस TreeMap के लिए किया गया था। निम्नलिखित कोड को देखो:केस-असंवेदनशील तुलनाकर्ता मेरे ट्रीमैप को तोड़ता है

TreeMap<String, String> treeMap = new TreeMap<>(new Comparator<String>() { 
     public int compare(String o1, String o2) { 
      return o1.toLowerCase().compareTo(o2.toLowerCase()); 
     } 
    }); 
    treeMap.put("abc", "Element1"); 
    treeMap.put("ABC", "Element2"); 

क्या मुझे लगता है कि मैंने किया है कि मैं एक नक्शा है कि इसकी कुंजी के अनुसार क्रमबद्ध किया जाता है, केस-संवेदी बनाया है है। दो अलग-अलग तत्वों में गैर-बराबर कुंजी होती हैं (abc और ABC) जिनकी तुलना 0 वापस आ जाएगी। मुझे उम्मीद है कि दोनों तत्वों का सिर्फ एक यादृच्छिक क्रम है। फिर भी, आदेश:

System.out.println("treeMap: " + treeMap); 

में हुई:

treeMap: {abc=Element2} 

कुंजी abc फिर से सौंपा गया है मूल्य Element2!

क्या कोई यह समझा सकता है कि यह कैसे हो सकता है और यदि यह TreeMap का वैध, दस्तावेज व्यवहार है?

+0

से कुछ का उपयोग करना चाहिए 'Comparator' एक * कुल आदेश * है। आपके मानचित्र में "एबीसी" और "एबीसी" के लिए इसका क्या अर्थ है? जो पहले आता है? –

+2

आपको अपना इरादा (यदि अप्रत्याशित) व्यवहार मिला है; आपका तुलनित्र केस-असंवेदनशील है, आपका नक्शा उस तुलनित्र का उपयोग करता है - इसलिए यह विस्तार से, केस-असंवेदनशील (w.r.t. कुंजी) भी है। * आपने अभी यह पता लगाया है कि कैसे मामला असंवेदनशील है * - आपके लिए कुडोस, लेकिन मुझे यहां "चौंकाने वाला" या "अवैध" कुछ भी नहीं दिख रहा है ... यह वही कर रहा है जो आपने * यह करने के लिए कहा था। – vaxquis

+0

संबंधित: [जावा ट्रीमैप कस्टम तुलनित्र अजीब व्यवहार] (https://stackoverflow.com/questions/30219835/java-treemap-custom-comparator-weird-behaviour) –

उत्तर

35

ऐसा इसलिए होता है क्योंकि TreeMapa.compareTo(b) == 0 के बराबर तत्व मानता है। यह the JavaDoc for TreeMap (जोर मेरा) में दर्ज है:

ध्यान दें कि आदेश एक पेड़ नक्शा द्वारा बनाए रखा, किसी भी क्रमबद्ध मानचित्र की तरह, और चाहे या नहीं एक स्पष्ट तुलनित्र प्रदान की जाती है, संगत equals साथ होना चाहिए अगर यह हल कर नक्शा इंटरफेस को सही तरीके से कार्यान्वित करना है। (Comparable या Comparator देखें equals के अनुरूप की एक सटीक परिभाषा के लिए।) यह इसलिए है क्योंकि मानचित्र इंटरफ़ेस equals आपरेशन के मामले में परिभाषित किया गया है, लेकिन एक हल कर नक्शा अपने compareTo (या compare) पद्धति का उपयोग करके सभी प्रमुख तुलना करता है, तो इस विधि के बराबर समझा जाने वाला दो कुंजियां क्रमबद्ध मानचित्र के दृष्टिकोण से हैं, बराबर। सॉर्ट किए गए मानचित्र का व्यवहार अच्छी तरह से परिभाषित किया गया है भले ही उसका ऑर्डर equals के साथ असंगत है; यह सिर्फ मानचित्र इंटरफ़ेस के सामान्य अनुबंध का पालन करने में विफल रहता है।

आपका तुलनित्र बराबर के अनुरूप नहीं है।

आप नहीं-बराबर बल्कि बराबर-अनदेखी दर-मामला तत्वों को बनाए रखना चाहते हैं, तो आपके तुलनित्र में जाँच के एक दूसरे स्तर में कहें, केस-संवेदी आदेश उपयोग करने के लिए:

public int compare(String o1, String o2) { 
     int cmp = o1.toLowerCase().compareTo(o2.toLowerCase()); 
     if (cmp != 0) return cmp; 

     return o1.compareTo(o2); 
    } 
+0

धन्यवाद, दोस्तों, त्वरित उत्तरों के लिए! अब मैं इसे दस्तावेज़ों में स्पष्ट रूप से बताता हूं, हालांकि मैं अभी भी जावा पक्ष पर इस व्यवहार को प्रतिबिंबित करता हूं। आखिरकार, ट्रीएप सॉर्टिंग के लिए है, और सॉर्टिंग संभवत: एक मामले-असंवेदनशील तरीके से ग्रंथों पर अक्सर किया जाता है। – javaxian

+0

@javaxian TreeMap एक पेड़ द्वारा समर्थित मानचित्र में वस्तुओं को बनाए रखने के लिए है, सॉर्टिंग पेड़ के उपयोग के दुष्प्रभाव का अधिक है। लेकिन हाँ, यह counterintuitive है क्योंकि यह मानचित्र इंटरफ़ेस की गारंटी का उल्लंघन करता है। जावा देवों का बहुत अच्छा नहीं है। – JAB

+7

@ जेएबी: मुझे यकीन नहीं है कि मैं सहमत हूं। 'ट्रीमैप' वर्ग 'मानचित्र' इंटरफ़ेस की गारंटी का पालन करता है, बशर्ते आप अपने इंटरफ़ेस की गारंटी का पालन करें! इसके दस्तावेज स्पष्ट रूप से बताता है कि तुलनित्र 'बराबर 'के अनुरूप होना चाहिए। इसी प्रकार, 'बराबर' और 'हैशकोड' संगत नहीं होने पर कोई भी 'हैश मैप' गलत व्यवहार करेगा-क्या आपको यह भी लगता है कि यह "बहुत अच्छा नहीं है"? मेरा मुद्दा है: अनुबंध दोनों तरीकों से जाते हैं। – wchargin

12

Comparator आप एक TreeMap के पास निर्धारित करता है न सिर्फ Map अंदर चाबियों का आदेश है, यह भी निर्धारित करता है कि दो चाबियाँ समान माना जाता है (वे समान माना जाता है जब compare() रिटर्न 0)।

इसलिए, आपके TreeMap में, "एबीसी" और "एबीसी" को समान कुंजी माना जाता है। Map एस समान कुंजी की अनुमति नहीं देता है, इसलिए दूसरा मान Element2 पहले मान Element1 को ओवरराइट करता है।

4

आप यह सुनिश्चित करने की जरूरत है कि उस मानचित्र के तत्वों की समानता तुलनित्र के अनुरूप है।कक्षा टिप्पणी से हवाला देते हुए:

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

1

स्वीकार्य उत्तर तकनीकी रूप से सही है, लेकिन समस्या के लिए मूर्खतापूर्ण समाधान को याद करता है।

आपको .equal() क्या है, इस पर विचार करने के लिए आपको स्थिर String.CASE_INSENSITIVE_ORDER तुलनाकर्ता प्रदान करना चाहिए या कम से कम String.compareToIgnoreCase() का उपयोग करना चाहिए।

स्थान संवेदनशील तुलना के लिए, आप java.text.Collator

+5

यह सही है कि डेवलपर्स को मौजूदा तुलनित्रों का उपयोग करना चाहिए या महंगा "लोअरकेस में परिवर्तित करें" विरोधी पैटर्न के बजाय समर्पित तुलना विधियों का उपयोग करना चाहिए। लेकिन यह समस्या का समाधान नहीं करता है। आपको अभी भी दो चरण तुलनित्र की आवश्यकता है। जावा 8 समाधान 'स्ट्रिंग' होगा। CASE_INSENSITIVE_ORDER.thenComparing (Comparator.naturalOrder()) '। – Holger

+0

@AndyTurner आप अपने स्वयं के लिखने के बजाय अंतर्निहित तुलनाकर्ताओं (या इस मामले में एक कॉललेटर) का उपयोग करने के बारे में बिल्कुल सही हैं। हालांकि, मेरे उत्पादन कोड में, मैं अपनी प्रस्तुति ऑर्डर पूर्णांक फ़ील्ड का उपयोग करके वस्तुओं की तुलना कर रहा था, जिसमें कुछ मामलों में समान मूल्य था। मैं यहां अपना उदाहरण अत्यधिक जटिल नहीं बनाना चाहता था, इसलिए मैं एक केस-असंवेदनशील स्ट्रिंग तुलनित्र के साथ गया। – javaxian

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