हाशपैप में मुख्य अस्तित्व की जाँच


309

क्या हशप में महत्वपूर्ण अस्तित्व की जाँच हमेशा आवश्यक है?

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

यह एक अच्छा प्रोग्रामिंग अभ्यास नहीं हो सकता है, लेकिन यह मुझे एक्सेस की संख्या को कम करने में मदद करेगा। या मुझसे यहां कुछ छूट रहा है?

[ अपडेट ] मेरे पास हाशप में शून्य मान नहीं है।


8
"इसलिए और अपवाद होता है" - क्या अपवाद है? यह java.util.HashMap से नहीं होगा ...
serg10 12

जवाबों:


513

क्या आप कभी भी एक शून्य मूल्य को स्टोर करते हैं? यदि नहीं, तो आप कर सकते हैं:

Foo value = map.get(key);
if (value != null) {
    ...
} else {
    // No such key
}

अन्यथा, आप अस्तित्व के लिए जाँच कर सकते हैं यदि आप एक शून्य मान लौटाते हैं:

Foo value = map.get(key);
if (value != null) {
    ...
} else {
    // Key might be present...
    if (map.containsKey(key)) {
       // Okay, there's a key but the value is null
    } else {
       // Definitely no such key
    }
}

1
@ शमूएल: केवल जब अशक्त संभव मूल्य है। यदि आपके पास निश्चित रूप से नक्शे में शून्य मान नहीं हैं, तो बस getठीक है, और जब आपको मूल्य की आवश्यकता होती है, तो दो लुक-अप करने से बचा जाता है।
जॉन स्कीट

हालांकि यह शायद एक उदाहरण के रूप में स्पष्ट है, आप if(value!=null || map.containsKey(key))दूसरे भाग के लिए भी लिख सकते हैं । कम से कम यदि आप उसी तरह से काम करना चाहते हैं - कोई दोहराया कोड नहीं। यह शॉर्ट सर्किटिंग के कारण काम करेगा ।
कलुब

66

कुंजी मौजूद है की जाँच करके आप कुछ हासिल नहीं करेंगे। यह कोड है HashMap:

@Override
public boolean containsKey(Object key) {
    Entry<K, V> m = getEntry(key);
    return m != null;
}

@Override
public V get(Object key) {
    Entry<K, V> m = getEntry(key);
    if (m != null) {
        return m.value;
    }
    return null;
}

बस जांचें कि क्या इसके लिए वापसी मूल्य get()अलग है null

यह HashMap स्रोत कोड है।


संसाधन:


2
इन विधियों के एक विशिष्ट कार्यान्वयन को दिखाने में क्या बात है?
जरबजो

2
यह समझाने के लिए कि ज्यादातर मामलों में, यह जाँचना कि कुंजी मौजूद है मूल्य प्राप्त करने की तुलना में एक ही समय लगेगा। इसलिए यह मूल्य प्राप्त करने से पहले वास्तव में मौजूद कुंजी की जांच करने के लिए कुछ भी अनुकूलन नहीं करेगा। मुझे पता है कि यह एक सामान्यीकरण है लेकिन यह समझने में मदद कर सकता है।
कॉलिन हेबर्ट

एक अच्छा लिंक grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/… (OpenJDK सन कोड से बहुत दृढ़ता से व्युत्पन्न है) और ऐसा लगता है कि यह गलत है। मैं Java6 के साथ Java5 के संस्करण की तुलना कर रहा था; वे इस क्षेत्र में अलग तरह से काम करते हैं (लेकिन दोनों सही हैं, जैसा कि आपके द्वारा पोस्ट किए गए स्निपेट्स हैं)।
डोनल फैलो

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

43

बेहतर तरीका है की containsKeyविधि का उपयोग करें HashMap। कल कोई न कोई नल को मैप में जोड़ देगा। आपको मुख्य उपस्थिति के बीच अंतर करना चाहिए और कुंजी में शून्य मान है।


हाँ। या पूरी तरह से भंडारण को रोकने के लिए हाशप को उप-वर्ग करें null
रोबू

1
आदिम प्रकारों के लिए 1+ मूल्य अनावश्यक कास्ट के रूप में इस उत्तर का उपयोग करने की आवश्यकता नहीं है
प्रशांत भाणकर

यह लिखने के लिए अधिक धाराप्रवाह भी है। अशक्त के लिए चेक (।) की तुलना में। हमें पढ़ने में आसान होने के बारे में अधिक चिंता करनी चाहिए, जो डेवलपर्स के समय को बचाता है, अधिकांश मामलों में कुछ मामूली अनुकूलन के बारे में। आवश्यक होने से पहले कम से कम अनुकूलन न करें।
मैक्स अप

23

क्या आपका मतलब है कि आपको कोड पसंद आ गया है

if(map.containsKey(key)) doSomethingWith(map.get(key))

सभी जगह ? फिर आपको बस जांच करनी चाहिए कि क्या map.get(key)वापस लौटा है या नहीं। वैसे, हाशपैप लापता चाबियों के अपवादों को नहीं फेंकते हैं, यह बदले में शून्य देता है। एक ही मामला है जहां containsKeyजरूरत है, जब आप अशक्त मानों को संचय कर रहे हैं, एक शून्य मान और एक लापता मूल्य के बीच अंतर करने के लिए, लेकिन यह आमतौर पर बुरा अभ्यास माना जाता है।


8

सिर्फ containsKey()स्पष्टता के लिए उपयोग करें । यह तेज़ है और कोड को साफ और पठनीय रखता है। संपूर्ण बिंदु HashMapयह है कि कुंजी लुकअप तेज है, बस सुनिश्चित करें hashCode()और equals()ठीक से कार्यान्वित किए गए हैं।



3

आप computeIfAbsent()मेथड का भी उपयोग कर सकते हैंHashMap कक्षा ।

निम्नलिखित उदाहरण में, mapलेन-देन की एक सूची (पूर्णांक) संग्रहीत करता है जो कुंजी (बैंक खाते का नाम) पर लागू होती है। के 2 लेन-देन को जोड़ने के लिए 100और 200करने के लिए checking_accountआप लिख सकते हैं:

HashMap<String, ArrayList<Integer>> map = new HashMap<>();
map.computeIfAbsent("checking_account", key -> new ArrayList<>())
   .add(100)
   .add(200);

इस तरह से आपको यह देखने की ज़रूरत नहीं है कि कुंजी checking_accountमौजूद है या नहीं।

  • यदि यह मौजूद नहीं है, तो एक लंबोदर अभिव्यक्ति द्वारा बनाई और वापस आ जाएगी।
  • यदि यह मौजूद है, तो कुंजी के लिए मान द्वारा लौटा दिया जाएगा computeIfAbsent()

वास्तव में सुरुचिपूर्ण! 👍


0

मैं आमतौर पर मुहावरे का उपयोग करता हूं

Object value = map.get(key);
if (value == null) {
    value = createValue(key);
    map.put(key, value);
}

इसका मतलब यह है कि यदि कुंजी गायब है, तो आप केवल दो बार नक्शे को हिट करते हैं


0
  1. यदि कुंजी वर्ग आपके पास है तो सुनिश्चित करें कि हैशकोड () और समान () तरीके लागू किए गए हैं।
  2. मूल रूप से HashMap की पहुंच O (1) होनी चाहिए, लेकिन गलत हैशकोड विधि के कार्यान्वयन के साथ यह O (n) हो जाता है, क्योंकि समान हैश कुंजी के साथ मान लिंक्ड सूची के रूप में संग्रहीत किया जाएगा।

0

जॉन स्कीट उत्तर एक कुशल तरीके से दो परिदृश्यों ( nullमूल्य के साथ नक्शा और मूल्य नहीं null) को अच्छी तरह से संबोधित करता है ।

संख्या प्रविष्टियों और दक्षता की चिंता के बारे में, मैं कुछ जोड़ना चाहूंगा।

मेरे पास 1.000 प्रविष्टियों के साथ एक हैशपॉप है और मैं दक्षता में सुधार देख रहा हूं। यदि हाशपैप को बहुत बार एक्सेस किया जा रहा है, तो हर एक्सेस पर प्रमुख अस्तित्व की जांच करने से एक बड़ा ओवरहेड हो जाएगा।

1.000 प्रविष्टियों वाला मानचित्र एक विशाल मानचित्र नहीं है।
साथ ही 5.000 या 10.000 प्रविष्टियों के साथ एक नक्शा।
Mapऐसे आयामों के साथ तेजी से पुनर्प्राप्ति बनाने के लिए डिज़ाइन किए गए हैं।

अब, यह मान लेता है कि hashCode()मानचित्र कुंजियाँ एक अच्छा वितरण प्रदान करती हैं।

यदि आप एक Integerकुंजी प्रकार के रूप में उपयोग कर सकते हैं , तो करें।
इसकी hashCode()विधि बहुत कुशल है क्योंकि अद्वितीय intमानों के लिए टकराव संभव नहीं है :

public final class Integer extends Number implements Comparable<Integer> {
    ...
    @Override
    public int hashCode() {
        return Integer.hashCode(value);
    }

    public static int hashCode(int value) {
        return value;
    }
    ...
}

यदि कुंजी के लिए, आपको एक और अंतर्निहित प्रकार का उपयोग करना होगा String, उदाहरण के लिए जो अक्सर उपयोग किया जाता है Map, तो आपके पास कुछ टकराव हो सकते हैं, लेकिन 1 हजार से लेकर कुछ हजारों वस्तुओं में Map, आपके पास इसके कुछ बहुत कम होने चाहिएString.hashCode() विधि के एक अच्छा वितरण प्रदान करता है।

यदि आप एक कस्टम प्रकार का उपयोग करते हैं, तो ओवरराइड करें hashCode()और equals()सही ढंग से और समग्र रूप से सुनिश्चित करें कि hashCode()उचित वितरण प्रदान करता है।
आप इसे संदर्भित करने के लिए आइटम 9 का Java Effectiveसंदर्भ ले सकते हैं।
यहाँ एक पोस्ट है कि जिस तरह से विवरण है।

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