जब एक और निर्माण बेहतर समय में काम कर सकता है, तो यह निर्धारित करने के लिए कि एक मूल्य के लिए (एक कार्य के लिए) यह निर्धारित करने के लिए कि हाशप का उपयोग क्यों किया जाना चाहिए?


9

जब मैं हाल ही में एक बड़ी कंपनी में काम कर रहा था, मैंने देखा कि वहां के प्रोग्रामर इस कोडिंग शैली का पालन करते हैं:

मान लीजिए मेरे पास एक फ़ंक्शन है जो इनपुट ए, 21 है अगर इनपुट बी, और 45 है तो इनपुट सी।

इसलिए मैं फ़ंक्शन हस्ताक्षर को इस प्रकार लिख सकता हूं:

int foo(String s){
    if(s.equals("A"))      return 12;
    else if(s.equals("B")) return 21;
    else if(s.equals("C")) return 45;
    else throw new RuntimeException("Invalid input to function foo");
}

लेकिन कोड समीक्षा पर मुझे फ़ंक्शन को निम्नलिखित में बदलने के लिए कहा गया था:

int foo(String s){
    HashMap<String, Integer> map = new HashMap<String, Integer>();
    map.put("A", 12);
    map.put("B", 21);
    map.put("C", 45);
    return map.get(s);
}

मैं खुद को नहीं समझा सकता कि दूसरा कोड पहले से बेहतर क्यों है। दूसरा कोड चलने में निश्चित रूप से अधिक समय लगेगा।

दूसरे कोड का उपयोग करने का एकमात्र कारण यह हो सकता है कि यह बेहतर पठनीयता प्रदान करता है। लेकिन अगर फ़ंक्शन को कई बार कॉल किया जा रहा है, तो क्या दूसरा फ़ंक्शन उपयोगिता के चलने के समय को धीमा नहीं करेगा?

आप इस बारे में क्या सोचते हैं?


4
तीन मूल्यों के लिए, एक नक्शा ओवरकिल की तरह लगता है (की switchतुलना में अधिक उपयुक्त लगता है if-else)। लेकिन कुछ बिंदु पर, यह समस्याग्रस्त हो जाता है। मैप का उपयोग करने का मुख्य लाभ यह है कि आप इसे फाइल या टेबल आदि से लोड कर सकते हैं। यदि आप मैप पर इनपुट को हार्ड-कोड कर रहे हैं, तो मुझे एक स्विच पर बहुत अधिक मूल्य नहीं दिखाई दे रहा है।
जिमीजैम

जवाबों:


17

मुद्दा यह है कि फ़ंक्शन के बाहर हैशम के निर्माण को स्थानांतरित करें और इसे एक बार करें (या अन्यथा से कम बार)।

private static final Map<String, Integer> map;
static{
    Map<String, Integer> temp = new HashMap<String, Integer>();
    temp.put("A", 12);
    temp.put("B", 21);
    temp.put("C", 45);
    map = Collections.unmodifiableMap(temp);//make immutable
}

int foo(String s){
    if(!map.containsKey(s))
        throw new RuntimeException("Invalid input to function foo");

    return map.get(s);
}

हालाँकि java7 तब से है जब स्विच में तार (अंतिम) तार होते हैं:

int foo(String s){
    switch(s){
    case "A":
        return 12;
    case "B": 
        return 21;
    case "C": 
        return 45;
    default: throw new RuntimeException("Invalid input to function foo");
}

1
मैं यह नहीं देखता कि यह कैसे ओपीएस सवाल का जवाब देता है, इसलिए वहां -1। लेकिन स्विच का सुझाव देने के लिए +1।
user949300

यह दिखाता है कि कोडिंग शैली को वास्तव में लागू करने और प्रदर्शन में सुधार करने के लिए कैसे ठीक से लागू किया जाए। यह अभी भी 3 विकल्पों के लिए समझ में नहीं आता है, लेकिन मूल कोड शायद बहुत लंबा था।
फ्लोरियन एफ

12

आपके दूसरे उदाहरण में, Mapअतिरेक आरंभीकरण से बचने के लिए एक निजी स्थिर सदस्य होना चाहिए।

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

दूसरे शब्दों में, मैप लुकिंग O (1) है, जबकि ifs O (n) हैं जहां n संभव इनपुट की संख्या है।

मानचित्र निर्माण O (n) है, लेकिन केवल एक बार किया जाता है यदि यह स्थिर स्थिर स्थिति है। बार-बार किए गए लुकअप के लिए, मैप ifलंबे समय तक स्टेटमेंट्स को बेहतर बनाएगा , थोड़े समय के लिए जब प्रोग्राम शुरू हो रहा हो (या भाषा के आधार पर क्लास को लोड किया गया हो)।

कहा जा रहा है कि, मानचित्र इस नौकरी के लिए हमेशा सही उपकरण नहीं है । यह बहुत अच्छा है जब बहुत सारे मूल्य होते हैं, या मूल्यों को एक पाठ फ़ाइल, उपयोगकर्ता इनपुट या डेटाबेस के माध्यम से कॉन्फ़िगर किया जाना चाहिए (जिस स्थिति में नक्शा कैश के रूप में कार्य करता है)।


हां, बड़ी मात्रा में मानों के लिए, मानचित्र बेहतर प्रदर्शन करेगा। लेकिन मूल्यों की मात्रा तय है, और यह तीन है।
रेमकोगर्लिच

मानचित्र का निर्माण ओ (एन) है केवल इसमें खोज ओ (1) है।
Pieter B

अच्छे अंक, मैंने अपना उत्तर स्पष्ट कर दिया।

मानचित्र में ऑटो-अनबॉक्सिंग की भी आवश्यकता होती है जो प्रदर्शन को बहुत कम प्रभावित करता है।
user949300

@ user949300 जावा में, हाँ, और प्रश्न में कोड जावा प्रतीत होता है। हालांकि, यह किसी भी भाषा से टैग नहीं किया है, और दृष्टिकोण कई भाषाओं (सहित सी # और सी ++, न तो जिनमें से मुक्केबाजी की आवश्यकता है) में काम करता है।

3

सॉफ्टवेयर में दो गति हैं: कोड लिखने / पढ़ने / डिबग करने में लगने वाला समय; और कोड निष्पादित करने में लगने वाला समय।

यदि आप मुझे (और आपके कोड समीक्षकों को) समझा सकते हैं कि हैशमैप फ़ंक्शन वास्तव में if / if / की तुलना में धीमा है (स्थैतिक हैशमैप बनाने के लिए फिर से शुरू करने के बाद) और आप मुझे / समीक्षकों को समझा सकते हैं कि इसकी वास्तविक बनाने के लिए पर्याप्त समय है अंतर है, तो आगे बढ़ो और अगर / किसी और के साथ हैशमैप को प्रतिस्थापित करें।

अन्यथा, हैशमप कोड प्रमुख रूप से पठनीय है; और (शायद) बगफ्री; आप इसे देख कर जल्दी से निर्धारित कर सकते हैं। यदि आप वास्तव में इसका अध्ययन किए बिना / अन्यथा के बारे में एक ही बात नहीं कह सकते हैं; जब विकल्पों में से सैकड़ों देखते हैं अंतर और भी अधिक अतिशयोक्तिपूर्ण है।


3
ठीक है, कि आपत्ति तब होती है जब कोई एक स्विच के बजाय तुलना करता है ...
डेडुप्लिकेटर

इसके अलावा अगर आप एक पंक्ति में इफ-स्टेटमेंट लिखते हैं, तो अलग हो जाता है।
gnasher729

2
हैशमैप निर्माण को कहीं और रखकर, आप केवल यह पता लगाने के लिए कठिन बना रहे हैं कि वास्तव में क्या होता है। फ़ंक्शन की वास्तविक प्रभाव क्या है, यह जानने के लिए आपको उन कुंजियों और मानों को देखना होगा।
रेमकोगर्लिच

2

मैं हाशपैप शैली के उत्तर को बहुत पसंद करता हूं।

इसके लिए एक मीट्रिक है

साइक्लोमैटिक कॉम्प्लेक्सिटी नामक एक कोड गुणवत्ता मीट्रिक है । (यह मीट्रिक मूल रूप से कोड के माध्यम से अलग-अलग रास्ते की संख्या की गणना कैसे की गणना करने के cyclomatic जटिलता )।

हर संभव निष्पादन पथ के लिए एक विधि कठिन और कठिन दोनों हो जाती है और शुद्धता के लिए पूरी तरह से परीक्षण।

यह इस तथ्य पर उबलता है कि "कीवर्ड को नियंत्रित करना" जैसे: ifs, elses, whiles, आदि ... गलत बूलियन परीक्षण जो गलत हो सकते हैं। "कीवर्ड को नियंत्रित करने" के बार-बार उपयोग नाजुक कोड पैदा करता है।

अतिरिक्त फायदे

इसके अलावा, "मानचित्र-आधारित दृष्टिकोण" डेवलपर्स को इनपुट-आउटपुट जोड़े के बारे में सोचने के लिए प्रोत्साहित करता है जो कि एक डेटासेट के रूप में निकाला जाता है, जिसे पुन: उपयोग किया जा सकता है, रनटाइम में हेरफेर किया जा सकता है, परीक्षण किया जा सकता है और सत्यापित किया जा सकता है। उदाहरण के लिए, नीचे मैंने "फू" को फिर से लिखा है ताकि हम स्थायी रूप से "ए-> 12, बी-> 21, सी-> 45" में बंद न हों:

int foo(String s){
    HashMap<String, Integer> map = getCurrentMapping();
    return map.get(s);
}

rachet_freak अपने उत्तर में इस प्रकार के रिफ्लेक्टर का उल्लेख करता है, वह गति और पुन: उपयोग के लिए तर्क देता है, मैं रनटाइम लचीलेपन के लिए बहस कर रहा हूं (हालांकि एक अपरिवर्तनीय संग्रह का उपयोग करने से स्थिति के आधार पर भारी लाभ हो सकते हैं)


1
उस रनटाइम लचीलेपन को जोड़ना या तो एक बेहतरीन फॉरवर्ड लुकिंग आइडिया है, या ज़रूरत से ज़्यादा-एंगेजिंग, जो कि हो रहा है, यह पता लगाना बहुत मुश्किल है। :-)।
user949300

@JimmyJames लिंक मेरे लिए काम करता है: यह है: leepoint.net/principles_and_practices/complexity/…
इवान

1
@ user949300 मुद्दा यह है कि "फू" विधि का समर्थन करने वाला कुंजी / मान डेटा एक अलग अवधारणा है जो स्पष्टता के कुछ रूप को पार कर सकती है । मानचित्र को अलग करने के लिए आप जो कोड लिखना चाहते हैं, वह इस बात पर निर्भर करेगा कि मानचित्र में कितनी वस्तुएँ हैं और कितनी बार उन वस्तुओं को बदलना पड़ सकता है।
इवान

1
@ कारण मैं अगर-बाकी श्रृंखला से बाहर खींच करने का सुझाव के user949300 यह है कि मैंने देखा है अगर-किसी और चेन समूहों में मौजूद है। Roaches तरह की किंडा, अगर वहाँ एक एक अगर-किसी और श्रृंखला पर आधारित पद्धति है वहाँ की संभावना एक समान / समान है, तो-और कुछ चेन के साथ कोड आधार में कहीं एक और तरीका है। यदि हम मान लें कि मानचित्र को निकालने से लाभांश मिलता है तो अन्य तरीके हो सकते हैं जो समान लुक-अप / स्विच जैसी तर्क संरचना का उपयोग करते हैं।
इवान

मैं भी डुप्लिकेट, लगभग समान देखा है यदि / को अवरोधित कर देते जगह सभी बिखरे हुए। खैर डाल
जॉन Chesterfield

1

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

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

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

def foo(s):
    return {
               "A" : 12,
               "B" : 21,
               "C" : 45,
           }[s]

कोड के पुनर्गठन क्रम को कम करने के विचार योग्यता है, लेकिन मैं बहुत बल्कि एक संकलक का उपयोग करेंगे अपने आप को इतना है कि उत्तोलकों की तुलना में आम सेटअप।


-1 सवाल का जवाब नहीं।
Pieter B

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

2
@JonChesterfield यह उत्तर मूल रूप से "एक बेहतर भाषा का उपयोग" है, जो शायद ही कभी सहायक होता है।
वालपेन

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

कुछ पुराने जावा कोड में, मुझे कुछ समान के लिए कुछ मानचित्रों की आवश्यकता थी, इसलिए 2-डी सरणियों के एन-आयामी सरणियों को मानचित्र में बदलने के लिए थोड़ी उपयोगिता लिखी। थोड़ा हैकी लेकिन अच्छा काम किया। यह उत्तर जोंसी अंकन का समर्थन करने के लिए पाइथन / जेएस की शक्ति को इतनी आसानी से और आसानी से इंगित करता है।
user949300
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.