जावास्क्रिप्ट हैशमप समतुल्य


353

जैसा कि इस उत्तर पर अपडेट 3 में स्पष्ट है , यह संकेतन:

var hash = {};
hash[X]

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

यह देखते हुए - क्या जावास्क्रिप्ट में हैशमैप्स का कोई कुशल कार्यान्वयन है? (उदाहरण के लिए, 2 का Google परिणाम javascript hashmapकिसी भी ऑपरेशन के लिए एक कार्यान्वयन है जो O (n) है। विभिन्न अन्य परिणाम इस तथ्य की अनदेखी करते हैं कि समतुल्य स्ट्रिंग प्रतिनिधित्व वाली विभिन्न वस्तुएं एक-दूसरे को अधिलेखित करती हैं।


1
@ कोलाडीयू: एडिट के लिए क्षमा करें, लेकिन शीर्षक में "मैप" वास्तव में भ्रामक था। यदि आप असहमत हैं तो रोल बैक करें, मेरा इरादा संरक्षक बनाने का नहीं था। :)
टॉमालक

6
@ कलैदु: आप जावास्क्रिप्ट के बारे में बहुत सारे प्रश्न पूछते हैं। अच्छे प्रश्न हैं। मुझे वह पसंद है।
कुछ

2
@ कोलियु: इसके अलावा, क्या आप उस Google परिणाम से लिंक कर सकते हैं जिसका आप उल्लेख करते हैं? Google के विभिन्न स्थानीय संस्करण अलग-अलग परिणाम लौटाते हैं, आपके द्वारा लागू किया गया कार्यान्वयन मेरे लिए भी दिखाई नहीं देता है।
तोमलक

@Tomalak: मैं बस एक ही बात लिखने जा रहा था!
कुछ

3
@Claudiu नहीं, गूगल से लिंक न करें। उस पृष्ठ से लिंक करें जिसके बारे में आप बात कर रहे थे (जो आप Google के माध्यम से खोजने के लिए हुए थे)। Google से लिंक करने में सभी समस्याओं के बारे में बताया गया है कि क्या खोजना है: स्थान या खोज इतिहास के आधार पर Google कस्टमाइज़िंग परिणाम, समय के साथ Google के परिणाम बदल रहे हैं (वर्तमान में, यह उस खोज के लिए शीर्ष परिणाम है) और कुछ और जो इसे बना सकते हैं अलग-अलग परिणाम दिखाएं।
जैस्पर

जवाबों:


369

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

उदाहरण:

var key = function(obj){
  // some unique object-dependent key
  return obj.totallyUniqueEmployeeIdKey; // just an example
};

var dict = {};

dict[key(obj1)] = obj1;
dict[key(obj2)] = obj2;

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

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

कुंजी फ़ंक्शन ऑब्जेक्ट की सही विशेषताओं का चयन करने के रूप में सरल हो सकता है, उदाहरण के लिए, एक कुंजी, या कुंजियों का एक सेट, जो पहले से ही अद्वितीय हैं, चाबियों का एक संयोजन, जो एक साथ अद्वितीय हैं, या कुछ क्रिप्टोग्राफ़िक हैश का उपयोग करने के रूप में जटिल हैं में DojoX एन्कोडिंग , या DojoX UUID । हालांकि बाद वाले समाधान अद्वितीय कुंजी पैदा कर सकते हैं, व्यक्तिगत रूप से मैं उन्हें हर कीमत पर बचने की कोशिश करता हूं, खासकर, अगर मुझे पता है कि मेरी वस्तुओं को अद्वितीय क्या है।

2014 में अपडेट: 2008 में वापस उत्तर दिया गया इस सरल समाधान को अभी भी अधिक स्पष्टीकरण की आवश्यकता है। मुझे एक प्रश्नोत्तर फॉर्म में विचार स्पष्ट करने दें।

आपके समाधान में असली हैश नहीं है। कहाँ है???

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

आप कैसे जानते हैं कि वे हैश का उपयोग करते हैं?

कुंजी द्वारा पता योग्य वस्तुओं का संग्रह रखने के तीन प्रमुख तरीके हैं:

  • अक्रमित। इस मामले में किसी वस्तु को उसकी कुंजी द्वारा पुनः प्राप्त करने के लिए जब हम उसे ढूंढते हैं तो हमें सभी कुंजियों को रोकना पड़ता है। औसतन यह n / 2 तुलना लेगा।
  • आदेश दिया।
    • उदाहरण # 1: एक सॉर्ट किया गया सरणी - एक द्विआधारी खोज हम ~ लॉग 2 (एन) औसत पर तुलना के बाद हमारी कुंजी पाएंगे। काफी बेहतर।
    • उदाहरण # 2: एक पेड़। फिर से यह ~ लॉग (n) प्रयास होगा।
  • हैश टेबल। औसतन इसके लिए एक निरंतर समय की आवश्यकता होती है। तुलना करें: O (n) बनाम O (लॉग एन) बनाम O (1)। बूम।

स्पष्ट रूप से जावास्क्रिप्ट ऑब्जेक्ट सामान्य मामलों को संभालने के लिए किसी न किसी रूप में हैश टेबल का उपयोग करते हैं।

क्या ब्राउज़र विक्रेता वास्तव में हैश टेबल का उपयोग करते हैं ???

वास्तव में।

क्या वे टकरावों को संभालते हैं?

हाँ। ऊपर देखो। यदि आपको असमान तारों पर एक टकराव मिला, तो कृपया एक विक्रेता के साथ बग दर्ज करने में संकोच न करें।

तो आपका विचार क्या है?

यदि आप किसी वस्तु को हैश करना चाहते हैं, तो वह खोज करें जो इसे विशिष्ट बनाती है और इसे एक कुंजी के रूप में उपयोग करें। वास्तविक हैश की गणना करने या हैश तालिकाओं का अनुकरण करने की कोशिश न करें - यह पहले से ही अंतर्निहित जावास्क्रिप्ट ऑब्जेक्ट द्वारा कुशलतापूर्वक नियंत्रित किया जाता है।

जावास्क्रिप्ट के साथ इस कुंजी का उपयोग करें Object का उपयोग इसकी अंतर्निहित हैश तालिका का लाभ उठाने के लिए करें, जबकि डिफ़ॉल्ट संपत्तियों के साथ संभावित झड़पों को स्पष्ट करते हुए।

आरंभ करने के लिए उदाहरण:

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

मैंने आपके सुझाव का उपयोग किया और उपयोगकर्ता नाम का उपयोग करके सभी वस्तुओं को कैश कर दिया। लेकिन कुछ बुद्धिमान व्यक्ति का नाम "toString" है, जो एक अंतर्निहित संपत्ति है! अब मुझे क्या करना चाहिए?

जाहिर है, अगर यह दूर से भी संभव है कि परिणामी कुंजी में विशेष रूप से लैटिन वर्ण होंगे, तो आपको इसके बारे में कुछ करना चाहिए। उदाहरण के लिए, किसी भी गैर-लैटिन यूनिकोड चरित्र को आप शुरू में या अंत में डिफ़ॉल्ट गुणों के साथ संयुक्त करें: "#toString", "#MarySmith"। यदि एक समग्र कुंजी का उपयोग किया जाता है, तो कुछ प्रकार के गैर-लैटिन परिसीमक का उपयोग करके अलग-अलग घटक होते हैं: "नाम, शहर, राज्य"।

सामान्य तौर पर यह वह जगह है, जहां हमें रचनात्मक होना है, और दी गई सीमाओं (विशिष्टता, डिफ़ॉल्ट गुणों के साथ संभावित संघर्ष) के साथ सबसे आसान कुंजी का चयन करना है।

नोट: अद्वितीय कुंजी परिभाषा से नहीं टकराती हैं, जबकि संभावित हैश क्लैश अंतर्निहित द्वारा नियंत्रित किए जाएंगे Object

आपको औद्योगिक समाधान क्यों पसंद नहीं है?

IMHO, सबसे अच्छा कोड कोई कोड नहीं है: इसमें कोई त्रुटि नहीं है, कोई रखरखाव की आवश्यकता नहीं है, समझने में आसान है, और तुरंत निष्पादित करता है। सभी "जावास्क्रिप्ट में हैश टेबल" मैंने देखा था> कोड की 100 लाइनें, और कई ऑब्जेक्ट शामिल थे। इसकी तुलना करें:dict[key] = value

एक और बिंदु: क्या यह एक निम्न-स्तरीय भाषा में लिखी गई एक प्रधान वस्तु के प्रदर्शन को हराकर संभव है, जो पहले से ही लागू है, उसे लागू करने के लिए जावास्क्रिप्ट और बहुत ही मौलिक वस्तुओं का उपयोग करना?

मैं अभी भी किसी भी कुंजी के बिना मेरी वस्तुओं हैश करना चाहता हूँ!

हम भाग्य में हैं: ECMAScript 6 (मध्य 2015 रिलीज़ के लिए अनुसूचित, व्यापक रूप से बनने के 1-2 साल बाद देना या लेना) मानचित्र और सेट को परिभाषित करता है ।

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

एमडीएन से तुलनात्मक विराम :

ऑब्जेक्ट मैप्स के समान हैं जिसमें दोनों आपको मानों की कुंजी सेट करने देते हैं, उन मानों को पुनः प्राप्त करते हैं, कुंजियों को हटाते हैं, और यह पता लगाते हैं कि क्या कुंजी में कुछ संग्रहीत है। इस वजह से (और क्योंकि कोई अंतर्निहित विकल्प नहीं थे), वस्तुओं का उपयोग ऐतिहासिक रूप से मानचित्र के रूप में किया गया है; हालाँकि, ऐसे कुछ महत्वपूर्ण अंतर हैं जो कुछ मामलों में मानचित्र को बेहतर बनाने का उपयोग करते हैं:

  • किसी ऑब्जेक्ट की कुंजी स्ट्रिंग्स और सिंबल हैं, जबकि वे फ़ंक्शंस, ऑब्जेक्ट्स और किसी भी आदिम सहित किसी मैप के लिए कोई भी मूल्य हो सकते हैं।
  • मानचित्र में कुंजियों का आदेश दिया जाता है, जबकि ऑब्जेक्ट में जोड़े गए कुंजी नहीं हैं। इस प्रकार, जब इस पर पुनरावृत्ति होती है, तो एक मैप ऑब्जेक्ट प्रविष्टि के क्रम में चाबियाँ देता है।
  • आप आकार की संपत्ति के साथ आसानी से मानचित्र का आकार प्राप्त कर सकते हैं, जबकि किसी ऑब्जेक्ट में गुणों की संख्या मैन्युअल रूप से निर्धारित की जानी चाहिए।
  • एक मानचित्र एक चलने योग्य है और इस प्रकार इसे सीधे पुनरावृत्त किया जा सकता है, जबकि किसी ऑब्जेक्ट पर पुनरावृत्ति करने के लिए कुछ फैशन में इसकी कुंजी प्राप्त करना और उन पर पुनरावृत्ति करना आवश्यक है।
  • ऑब्जेक्ट में एक प्रोटोटाइप होता है, इसलिए मानचित्र में डिफ़ॉल्ट कुंजियाँ होती हैं जो आपकी कुंजियों से टकरा सकती हैं यदि आप सावधान नहीं हैं। ES5 के रूप में यह नक्शा = Object.create (अशक्त) का उपयोग करके बाईपास किया जा सकता है, लेकिन यह शायद ही कभी किया जाता है।
  • अक्सर जोड़े को जोड़ने और मुख्य जोड़े को हटाने के लिए एक नक्शा बेहतर प्रदर्शन कर सकता है।

13
यह एक उचित नक्शे की तरह नहीं दिखता है, क्योंकि आप टकरावों को संभालते नहीं हैं। यदि यह सही होता है: हैश (obj1) == हैश (obj2), तो आप अपना डेटा खोने जा रहे हैं।
बीफदर डे

32
स्वर्ग तब आपकी मदद करता है जब आपके सिस्टम में "PAUL AINLEY" और "PAULA INLEY" दोनों रजिस्टर होते हैं ...
मैट R

34
@MattR वास्तव में आपका उदाहरण एक मॉक हैश फ़ंक्शन के साथ स्वर्ग की सहायता के बिना ठीक से काम करेगा। मुझे उम्मीद है कि अन्य पाठकों को एहसास होगा कि एक अलग तकनीक को प्रदर्शित करने के लिए प्लेसहोल्डर के रूप में एक अति-सरलीकृत गैर-यथार्थवादी हैश फ़ंक्शन का उपयोग किया गया था। दोनों कोड टिप्पणियाँ, और उत्तर में ही तनाव है कि यह वास्तविक नहीं है। उत्तर के अंतिम पैराग्राफ में उचित कुंजियों के चयन पर चर्चा की गई है।
यूजीन लाजुटकिन

6
@ यूजीनलाज़ुटकिन - आप अभी भी गलत हैं, मुझे डर है। आपका उदाहरण अभी भी हैश टक्करों के लिए प्रवण है। ऐसा मत सोचो कि बस अंतिम नाम पहले डाल किसी तरह आपकी मदद करेगा!
मैट आर

3
@EugeneLazutkin अधिकांश लोगों ने पढ़ा नहीं है कि आपने इस BESORE ES6 का उत्तर दिया है यहां तक ​​कि यह भी प्रतीत होता है ... मुझे अपने गहन जेएस ज्ञान के लिए बधाई दें।
गेब्रियल एंड्रेस ब्रानकोलिनी 20

171

समस्या का विवरण

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

जब वस्तुओं को मानचित्रों के रूप में उपयोग करते हैं, तो आपको याद रखना होगा कि कुंजी स्ट्रिंग मान में बदल जाएगी toString(), जिसके परिणामस्वरूप मानचित्रण 5और '5'समान मूल्य और सभी ऑब्जेक्ट्स जो कि toString()अनुक्रमित मूल्य के लिए विधि को अधिलेखित नहीं करते हैं '[object Object]'। यदि आप जांच नहीं करते हैं तो आप अनपेक्षित रूप से इसके विरासत वाले गुणों तक पहुंच सकते हैं hasOwnProperty()

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

यूजीन का समाधान

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

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

मनमानी वस्तुओं के लिए एक अद्वितीय हैश मान प्राप्त करने के लिए, एक संभावना एक वैश्विक काउंटर का उपयोग करना है और ऑब्जेक्ट में ही हैश मूल्य को कैश करना है (जैसे नाम की संपत्ति में __hash)।

एक हैश फ़ंक्शन जो ऐसा करता है और यह दोनों आदिम मूल्यों और वस्तुओं के लिए काम करता है:

function hash(value) {
    return (typeof value) + ' ' + (value instanceof Object ?
        (value.__hash || (value.__hash = ++arguments.callee.current)) :
        value.toString());
}

hash.current = 0;

इस फ़ंक्शन का उपयोग यूजीन द्वारा वर्णित के रूप में किया जा सकता है। सुविधा के लिए, हम इसे एक Mapकक्षा में लपेटेंगे।

मेरा Mapकार्यान्वयन

निम्नलिखित कार्यान्वयन अतिरिक्त रूप से कुंजी-मूल्य-जोड़े को एक दोहरी लिंक की गई सूची में संग्रहीत करेगा ताकि कुंजी और मान दोनों पर तेजी से पुनरावृत्ति की अनुमति दी जा सके। अपने स्वयं के हैश फ़ंक्शन की आपूर्ति करने के लिए, आप hash()निर्माण के बाद इंस्टेंस की विधि को ओवरराइट कर सकते हैं ।

// linking the key-value-pairs is optional
// if no argument is provided, linkItems === undefined, i.e. !== false
// --> linking will be enabled
function Map(linkItems) {
    this.current = undefined;
    this.size = 0;

    if(linkItems === false)
        this.disableLinking();
}

Map.noop = function() {
    return this;
};

Map.illegal = function() {
    throw new Error("illegal operation for maps without linking");
};

// map initialisation from existing object
// doesn't add inherited properties if not explicitly instructed to:
// omitting foreignKeys means foreignKeys === undefined, i.e. == false
// --> inherited properties won't be added
Map.from = function(obj, foreignKeys) {
    var map = new Map;

    for(var prop in obj) {
        if(foreignKeys || obj.hasOwnProperty(prop))
            map.put(prop, obj[prop]);
    }

    return map;
};

Map.prototype.disableLinking = function() {
    this.link = Map.noop;
    this.unlink = Map.noop;
    this.disableLinking = Map.noop;
    this.next = Map.illegal;
    this.key = Map.illegal;
    this.value = Map.illegal;
    this.removeAll = Map.illegal;

    return this;
};

// overwrite in Map instance if necessary
Map.prototype.hash = function(value) {
    return (typeof value) + ' ' + (value instanceof Object ?
        (value.__hash || (value.__hash = ++arguments.callee.current)) :
        value.toString());
};

Map.prototype.hash.current = 0;

// --- mapping functions

Map.prototype.get = function(key) {
    var item = this[this.hash(key)];
    return item === undefined ? undefined : item.value;
};

Map.prototype.put = function(key, value) {
    var hash = this.hash(key);

    if(this[hash] === undefined) {
        var item = { key : key, value : value };
        this[hash] = item;

        this.link(item);
        ++this.size;
    }
    else this[hash].value = value;

    return this;
};

Map.prototype.remove = function(key) {
    var hash = this.hash(key);
    var item = this[hash];

    if(item !== undefined) {
        --this.size;
        this.unlink(item);

        delete this[hash];
    }

    return this;
};

// only works if linked
Map.prototype.removeAll = function() {
    while(this.size)
        this.remove(this.key());

    return this;
};

// --- linked list helper functions

Map.prototype.link = function(item) {
    if(this.size == 0) {
        item.prev = item;
        item.next = item;
        this.current = item;
    }
    else {
        item.prev = this.current.prev;
        item.prev.next = item;
        item.next = this.current;
        this.current.prev = item;
    }
};

Map.prototype.unlink = function(item) {
    if(this.size == 0)
        this.current = undefined;
    else {
        item.prev.next = item.next;
        item.next.prev = item.prev;
        if(item === this.current)
            this.current = item.next;
    }
};

// --- iterator functions - only work if map is linked

Map.prototype.next = function() {
    this.current = this.current.next;
};

Map.prototype.key = function() {
    return this.current.key;
};

Map.prototype.value = function() {
    return this.current.value;
};

उदाहरण

निम्न लिपि

var map = new Map;

map.put('spam', 'eggs').
    put('foo', 'bar').
    put('foo', 'baz').
    put({}, 'an object').
    put({}, 'another object').
    put(5, 'five').
    put(5, 'five again').
    put('5', 'another five');

for(var i = 0; i++ < map.size; map.next())
    document.writeln(map.hash(map.key()) + ' : ' + map.value());

यह उत्पादन उत्पन्न करता है:

string spam : eggs
string foo : baz
object 1 : an object
object 2 : another object
number 5 : five again
string 5 : another five

आगे के विचार

PEZ ने toString()विधि को अधिलेखित करने का सुझाव दिया , संभवतः हमारे हैश फ़ंक्शन के साथ। यह संभव नहीं है क्योंकि यह आदिम मूल्यों के लिए काम नहीं करता है ( toString()आदिम के लिए बदलना बहुत बुरा विचार है)। यदि हम toString()मनमाना वस्तुओं के लिए सार्थक मूल्यों को वापस करना चाहते हैं, तो हमें संशोधित करना होगा Object.prototype, जिसे कुछ लोग (स्वयं शामिल नहीं) वर्बोटेन मानते हैं


संपादित करें: मेरे Mapकार्यान्वयन का वर्तमान संस्करण और साथ ही अन्य जावास्क्रिप्ट उपहार यहां से प्राप्त किए जा सकते हैं


ES5 कैलली के उपयोग को दर्शाता है ( goo.gl/EeStE )। इसके बजाय, मैं सुझाव देता हूं Map._counter = 0, और मैप कंस्ट्रक्टर में करता हूं this._hash = 'object ' + Map._counter++। फिर हैश () बन जाता हैreturn (value && value._hash) || (typeof(value) + ' ' + String(value));
ब्रोफा

कोड का लिंक टूट गया है: mercurial.intuxication.org/hg/js-hacks/raw-file/tip/map.js
ahcox

hi @Christoph, क्या आप अपना लिंक अपडेट कर सकते हैं कि मैं आपके मानचित्र का कार्यान्वयन कहाँ से कर सकता हूँ?
न्यूमेनफोरलाइफ

2
@ jsc123: मैं उस पर गौर करूंगा - अभी के लिए आप रिपॉजिटरी का एक डंप pikacode.com/mercurial.intuxication.org/js-hacks.tar.gz
क्रिस्टोफ

58

मुझे पता है कि यह सवाल बहुत पुराना है, लेकिन आजकल बाहरी पुस्तकालयों के साथ कुछ बहुत बढ़िया समाधान हैं।

जावास्क्रिप्ट भी अपनी भाषा के Mapरूप में अच्छी तरह से प्रदान की है ।


2
यह 21 वीं सदी में आगे बढ़ने का रास्ता है। बहुत बुरा है कि मैंने कुछ बदसूरत घर के बने मानचित्र के साथ अपना कोड खत्म करने के बाद आपका पोस्ट पाया। WEEE को आपके उत्तर के लिए अधिक वोट की आवश्यकता है
फुंग डी। एक

1
Collections.js में कुछ कार्यान्वयन हैं, लेकिन मुझे अंडरस्कोर।जे या लॉश में कोई भी नहीं मिल सकता है ... आप अंडरस्कोर में क्या बात कर रहे थे जो उपयोगी होगा?
कोडबेलिंग

@CodeBling कोई विचार नहीं है। मुझे लगता है कि मैं इसे मानचित्र फ़ंक्शन के साथ भ्रमित कर रहा हूं। मैं इसे उत्तर से हटाने जा रहा हूं।
जेमल टॉम्स

3
ये उचित है। कलेक्शंस.जेएस पर विचार करने वाला कोई भी व्यक्ति इस बात से अवगत होना चाहिए कि यह वैश्विक एरे, फंक्शन, ऑब्जेक्ट और रेगेक्सप प्रोटोटाइप को एक समस्याग्रस्त फैशन में संशोधित करता है ( जिन मुद्दों का मैंने यहां सामना किया है उन्हें देखें )। हालाँकि मैं शुरू में संग्रह से बहुत खुश था। जेएस (और इस तरह यह जवाब), इसका उपयोग करने से जुड़े जोखिम बहुत अधिक थे, इसलिए मैंने इसे गिरा दिया। केवल kriskowal की v2 संग्रह की संग्रह। Js (विशेष रूप से, v2.0.2 +) वैश्विक प्रोटोटाइप संशोधनों को समाप्त करती है और उपयोग करने के लिए सुरक्षित है।
कोडबेलिंग

28

यहाँ जावा मैप के समान कुछ का उपयोग करने का एक आसान और सुविधाजनक तरीका है:

var map= {
        'map_name_1': map_value_1,
        'map_name_2': map_value_2,
        'map_name_3': map_value_3,
        'map_name_4': map_value_4
        }

और मूल्य प्राप्त करने के लिए:

alert( map['map_name_1'] );    // fives the value of map_value_1

......  etc  .....

2
यह केवल स्ट्रिंग कुंजियों के लिए काम करता है। मेरा मानना ​​है कि ओपी किसी भी प्रकार की कुंजी का उपयोग करने में रुचि रखता था।
फ्रैक्चर

26

ECMAScript 2015 (ES6) के अनुसार मानक जावास्क्रिप्ट में मानचित्र कार्यान्वयन है। जिसके बारे में और जानकारी यहाँ मिल सकती है

मूल उपयोग:

var myMap = new Map();
var keyString = "a string",
    keyObj = {},
    keyFunc = function () {};

// setting the values
myMap.set(keyString, "value associated with 'a string'");
myMap.set(keyObj, "value associated with keyObj");
myMap.set(keyFunc, "value associated with keyFunc");

myMap.size; // 3

// getting the values
myMap.get(keyString);    // "value associated with 'a string'"
myMap.get(keyObj);       // "value associated with keyObj"
myMap.get(keyFunc);      // "value associated with keyFunc"

21

आप ES6 WeakMapया का उपयोग कर सकते हैं Map:

  • WeakMaps कुंजी / मान मानचित्र हैं जिसमें कुंजियाँ ऑब्जेक्ट हैं।

  • Mapऑब्जेक्ट सरल कुंजी / मान मानचित्र हैं। किसी भी मूल्य (दोनों वस्तुओं और आदिम मूल्यों) को एक कुंजी या एक मूल्य के रूप में इस्तेमाल किया जा सकता है।

ध्यान रखें कि न तो व्यापक रूप से समर्थित है, लेकिन आप समर्थन करने के लिए ES6 शिम (मूल ES5 या ES5 शिम की आवश्यकता है ) का उपयोग कर सकते हैं Map, लेकिन नहीं WeakMap( देखें क्यों )।


2019 में वे बहुत अच्छी तरह से समर्थित हैं और अद्भुत तरीके हैं! developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
जुआन मेनेंडेज़

13

आपको वस्तु / मूल्य जोड़े के कुछ आंतरिक अवस्था जोड़े में संग्रहीत करना होगा

HashMap = function(){
  this._dict = [];
}
HashMap.prototype._get = function(key){
  for(var i=0, couplet; couplet = this._dict[i]; i++){
    if(couplet[0] === key){
      return couplet;
    }
  }
}
HashMap.prototype.put = function(key, value){
  var couplet = this._get(key);
  if(couplet){
    couplet[1] = value;
  }else{
    this._dict.push([key, value]);
  }
  return this; // for chaining
}
HashMap.prototype.get = function(key){
  var couplet = this._get(key);
  if(couplet){
    return couplet[1];
  }
}

और इसे इस तरह से उपयोग करें:

var color = {}; // unique object instance
var shape = {}; // unique object instance
var map = new HashMap();
map.put(color, "blue");
map.put(shape, "round");
console.log("Item is", map.get(color), "and", map.get(shape));

बेशक, यह कार्यान्वयन भी ओ (एन) की तर्ज पर कहीं है। ऊपर यूजीन के उदाहरण एक हैश पाने का एकमात्र तरीका है जो किसी भी प्रकार की गति के साथ काम करता है जिसे आप असली हैश से उम्मीद करते हैं।

अपडेट करें:

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

HashMap = function(){
  this._dict = {};
}
HashMap.prototype._shared = {id: 1};
HashMap.prototype.put = function put(key, value){
  if(typeof key == "object"){
    if(!key.hasOwnProperty._id){
      key.hasOwnProperty = function(key){
        return Object.prototype.hasOwnProperty.call(this, key);
      }
      key.hasOwnProperty._id = this._shared.id++;
    }
    this._dict[key.hasOwnProperty._id] = value;
  }else{
    this._dict[key] = value;
  }
  return this; // for chaining
}
HashMap.prototype.get = function get(key){
  if(typeof key == "object"){
    return this._dict[key.hasOwnProperty._id];
  }
  return this._dict[key];
}

यह संस्करण केवल थोड़ा तेज प्रतीत होता है, लेकिन सिद्धांत रूप में यह बड़े डेटा सेटों के लिए काफी तेज होगा।


एक साहचर्य सरणी, यानी 2-ट्यूपल्स की एक सरणी, एक मानचित्र है, न कि कोई हाशपॉइंट; हाशपॅप एक नक्शा है जो बेहतर प्रदर्शन के लिए हैश का उपयोग करता है।
एरिक कपलुन

सच है, लेकिन विषय पर बाल क्यों विभाजित करें? जावास्क्रिप्ट में कोई सच्चा हैश मैप बनाने का कोई तरीका नहीं है क्योंकि आपको ऑब्जेक्ट मेमोरी एड्रेस नहीं मिल सकते हैं। और जावास्क्रिप्ट की अंतर्निहित वस्तु कुंजी / मूल्य जोड़े (मेरे दूसरे उदाहरण में उपयोग किए गए) हैशमैप के रूप में कार्य कर सकते हैं, लेकिन जरूरी नहीं, क्योंकि यह ब्राउज़र में उपयोग किए जाने वाले रनटाइम पर निर्भर है कि लुकअप कैसे लागू किया जाता है।
४otted१ पर पॉटमैट

11

दुर्भाग्य से, उपरोक्त उत्तर में से कोई भी मेरे मामले के लिए अच्छा नहीं था: विभिन्न प्रमुख वस्तुओं में समान हैश कोड हो सकता है। इसलिए, मैंने एक सरल जावा-जैसा हैशपॉप संस्करण लिखा:

function HashMap() {
    this.buckets = {};
}

HashMap.prototype.put = function(key, value) {
    var hashCode = key.hashCode();
    var bucket = this.buckets[hashCode];
    if (!bucket) {
        bucket = new Array();
        this.buckets[hashCode] = bucket;
    }
    for (var i = 0; i < bucket.length; ++i) {
        if (bucket[i].key.equals(key)) {
            bucket[i].value = value;
            return;
        }
    }
    bucket.push({ key: key, value: value });
}

HashMap.prototype.get = function(key) {
    var hashCode = key.hashCode();
    var bucket = this.buckets[hashCode];
    if (!bucket) {
        return null;
    }
    for (var i = 0; i < bucket.length; ++i) {
        if (bucket[i].key.equals(key)) {
            return bucket[i].value;
        }
    }
}

HashMap.prototype.keys = function() {
    var keys = new Array();
    for (var hashKey in this.buckets) {
        var bucket = this.buckets[hashKey];
        for (var i = 0; i < bucket.length; ++i) {
            keys.push(bucket[i].key);
        }
    }
    return keys;
}

HashMap.prototype.values = function() {
    var values = new Array();
    for (var hashKey in this.buckets) {
        var bucket = this.buckets[hashKey];
        for (var i = 0; i < bucket.length; ++i) {
            values.push(bucket[i].value);
        }
    }
    return values;
}

नोट: प्रमुख वस्तुओं को हैशकोड () और समान () विधियों को "कार्यान्वित" करना चाहिए।


7
new Array()ओवर की प्राथमिकता []आपके कोड की पूर्ण जावा-समानता सुनिश्चित करना है? :)
एरिक कपलुन

6

मैंने एक जावास्क्रिप्ट हैशपॉप लागू किया है जो कोड http://github.com/lambder/HashMapJS/tree/master से प्राप्त किया जा सकता है

यहाँ कोड है:

/*
 =====================================================================
 @license MIT
 @author Lambder
 @copyright 2009 Lambder.
 @end
 =====================================================================
 */
var HashMap = function() {
  this.initialize();
}

HashMap.prototype = {
  hashkey_prefix: "<#HashMapHashkeyPerfix>",
  hashcode_field: "<#HashMapHashkeyPerfix>",

  initialize: function() {
    this.backing_hash = {};
    this.code = 0;
  },
  /*
   maps value to key returning previous assocciation
   */
  put: function(key, value) {
    var prev;
    if (key && value) {
      var hashCode = key[this.hashcode_field];
      if (hashCode) {
        prev = this.backing_hash[hashCode];
      } else {
        this.code += 1;
        hashCode = this.hashkey_prefix + this.code;
        key[this.hashcode_field] = hashCode;
      }
      this.backing_hash[hashCode] = value;
    }
    return prev;
  },
  /*
   returns value associated with given key
   */
  get: function(key) {
    var value;
    if (key) {
      var hashCode = key[this.hashcode_field];
      if (hashCode) {
        value = this.backing_hash[hashCode];
      }
    }
    return value;
  },
  /*
   deletes association by given key.
   Returns true if the assocciation existed, false otherwise
   */
  del: function(key) {
    var success = false;
    if (key) {
      var hashCode = key[this.hashcode_field];
      if (hashCode) {
        var prev = this.backing_hash[hashCode];
        this.backing_hash[hashCode] = undefined;
        if(prev !== undefined)
          success = true;
      }
    }
    return success;
  }
}

//// Usage

// creation

var my_map = new HashMap();

// insertion

var a_key = {};
var a_value = {struct: "structA"};
var b_key = {};
var b_value = {struct: "structB"};
var c_key = {};
var c_value = {struct: "structC"};

my_map.put(a_key, a_value);
my_map.put(b_key, b_value);
var prev_b = my_map.put(b_key, c_value);

// retrieval

if(my_map.get(a_key) !== a_value){
  throw("fail1")
}
if(my_map.get(b_key) !== c_value){
  throw("fail2")
}
if(prev_b !== b_value){
  throw("fail3")
}

// deletion

var a_existed = my_map.del(a_key);
var c_existed = my_map.del(c_key);
var a2_existed = my_map.del(a_key);

if(a_existed !== true){
  throw("fail4")
}
if(c_existed !== false){
  throw("fail5")
}
if(a2_existed !== false){
  throw("fail6")
}

2
आप एक ही ऑब्जेक्ट को कई HashMapएस में डालने के साथ काम नहीं करते हैं ।
एरिक कप्लून

5

ECMA6 में आप उपयोग कर सकते हैं WeakMap

उदाहरण:

var wm1 = new WeakMap(),
    wm2 = new WeakMap(),
    wm3 = new WeakMap();
var o1 = {},
    o2 = function(){},
    o3 = window;

wm1.set(o1, 37);
wm1.set(o2, "azerty");
wm2.set(o1, o2); // a value can be anything, including an object or a function
wm2.set(o3, undefined);
wm2.set(wm1, wm2); // keys and values can be any objects. Even WeakMaps!

wm1.get(o2); // "azerty"
wm2.get(o2); // undefined, because there is no value for o2 on wm2
wm2.get(o3); // undefined, because that is the set value

wm1.has(o2); // true
wm2.has(o2); // false
wm2.has(o3); // true (even if the value itself is 'undefined')

wm3.set(o1, 37);
wm3.get(o1); // 37
wm3.clear();
wm3.get(o1); // undefined, because wm3 was cleared and there is no value for o1 anymore

wm1.has(o1);   // true
wm1.delete(o1);
wm1.has(o1);   // false

परंतु:

Because of references being weak, WeakMap keys are not enumerable (i.e. there is no method giving you a list of the keys). 

ओह स्तुति jesus वे अंततः जावास्क्रिप्ट के लिए कमजोर संदर्भ जोड़ रहे हैं। यह समय के बारे में है ... उस के लिए +1, लेकिन यह वास्तव में उपयोग करने के लिए भयानक होगा क्योंकि संदर्भ कमजोर हैं
क्लाउडीयू

2

जावास्क्रिप्ट मानचित्र / हैशमैप में निर्मित नहीं होता है। इसे साहचर्य सरणी कहा जाना चाहिए ।

hash["X"]के बराबर है hash.X, लेकिन "X" को एक स्ट्रिंग चर के रूप में अनुमति देता है। दूसरे शब्दों में, hash[x]कार्यात्मक रूप से बराबर हैeval("hash."+x.toString())

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


2

मेरे जावास्क्रिप्ट हैश तालिका कार्यान्वयन का प्रयास करें: http://www.timdown.co.uk/jshashtable

यह हैशकोड () प्रमुख वस्तुओं की विधि के लिए दिखता है, या हैशटेबल ऑब्जेक्ट बनाते समय आप हैशिंग फ़ंक्शन की आपूर्ति कर सकते हैं।


2

यह एक बहुत मजबूत समाधान की तरह दिखता है: https://github.com/flesler/hashmap । यह समान दिखने वाले कार्यों और वस्तुओं के लिए भी अच्छी तरह से काम करेगा। इसका उपयोग करने वाली एकमात्र हैक एक अस्पष्ट सदस्य को इसे पहचानने के लिए एक वस्तु में जोड़ रही है। यदि आपका कार्यक्रम उस अस्पष्ट चर ( हशिद की तरह कुछ ) को अधिलेखित नहीं करता है , तो आप सुनहरे हैं।


2

यदि प्रदर्शन महत्वपूर्ण नहीं है (उदाहरण के लिए कुंजी की राशि अपेक्षाकृत छोटा है) और आप दूषित करते जैसे अतिरिक्त क्षेत्रों के साथ अपने (या शायद नहीं अपने) वस्तुओं नहीं करना चाहती _hash, _idआदि, हैं, तो आप इस तथ्य है कि का उपयोग कर सकते Array.prototype.indexOfरोजगार सख्त समानता। यहाँ एक सरल कार्यान्वयन है:

var Dict = (function(){
    // IE 8 and earlier has no Array.prototype.indexOf
    function indexOfPolyfill(val) {
      for (var i = 0, l = this.length; i < l; ++i) {
        if (this[i] === val) {
          return i;
        }
      }
      return -1;
    }

    function Dict(){
      this.keys = [];
      this.values = [];
      if (!this.keys.indexOf) {
        this.keys.indexOf = indexOfPolyfill;
      }
    };

    Dict.prototype.has = function(key){
      return this.keys.indexOf(key) != -1;
    };

    Dict.prototype.get = function(key, defaultValue){
      var index = this.keys.indexOf(key);
      return index == -1 ? defaultValue : this.values[index];
    };

    Dict.prototype.set = function(key, value){
      var index = this.keys.indexOf(key);
      if (index == -1) {
        this.keys.push(key);
        this.values.push(value);
      } else {
        var prevValue = this.values[index];
        this.values[index] = value;
        return prevValue;
      }
    };

    Dict.prototype.delete = function(key){
      var index = this.keys.indexOf(key);
      if (index != -1) {
        this.keys.splice(index, 1);
        return this.values.splice(index, 1)[0];
      }
    };

    Dict.prototype.clear = function(){
      this.keys.splice(0, this.keys.length);
      this.values.splice(0, this.values.length);
    };

    return Dict;
})();

उपयोग का उदाहरण:

var a = {}, b = {},
    c = { toString: function(){ return '1'; } },
    d = 1, s = '1', u = undefined, n = null,
    dict = new Dict();

// keys and values can be anything
dict.set(a, 'a');
dict.set(b, 'b');
dict.set(c, 'c');
dict.set(d, 'd');
dict.set(s, 's');
dict.set(u, 'u');
dict.set(n, 'n');

dict.get(a); // 'a'
dict.get(b); // 'b'
dict.get(s); // 's'
dict.get(u); // 'u'
dict.get(n); // 'n'
// etc.

ES6 WeakMap की तुलना में इसके दो मुद्दे हैं: O (n) खोज समय और गैर-कमजोरी (अर्थात यह मेमोरी लीक का कारण होगा यदि आप उपयोग नहीं करते हैं deleteया clearचाबियाँ जारी करते हैं)।


2

मेरा मानचित्र कार्यान्वयन, जो क्रिस्टोफ़ के उदाहरण से लिया गया है:

उदाहरण उपयोग:

var map = new Map();  //creates an "in-memory" map
var map = new Map("storageId");  //creates a map that is loaded/persisted using html5 storage

function Map(storageId) {
    this.current = undefined;
    this.size = 0;
    this.storageId = storageId;
    if (this.storageId) {
        this.keys = new Array();
        this.disableLinking();
    }
}

Map.noop = function() {
    return this;
};

Map.illegal = function() {
    throw new Error("illegal operation for maps without linking");
};

// map initialisation from existing object
// doesn't add inherited properties if not explicitly instructed to:
// omitting foreignKeys means foreignKeys === undefined, i.e. == false
// --> inherited properties won't be added
Map.from = function(obj, foreignKeys) {
    var map = new Map;
    for(var prop in obj) {
        if(foreignKeys || obj.hasOwnProperty(prop))
            map.put(prop, obj[prop]);
    }
    return map;
};

Map.prototype.disableLinking = function() {
    this.link = Map.noop;
    this.unlink = Map.noop;
    this.disableLinking = Map.noop;

    this.next = Map.illegal;
    this.key = Map.illegal;
    this.value = Map.illegal;
//    this.removeAll = Map.illegal;


    return this;
};

// overwrite in Map instance if necessary
Map.prototype.hash = function(value) {
    return (typeof value) + ' ' + (value instanceof Object ?
        (value.__hash || (value.__hash = ++arguments.callee.current)) :
        value.toString());
};

Map.prototype.hash.current = 0;

// --- mapping functions

Map.prototype.get = function(key) {
    var item = this[this.hash(key)];
    if (item === undefined) {
        if (this.storageId) {
            try {
                var itemStr = localStorage.getItem(this.storageId + key);
                if (itemStr && itemStr !== 'undefined') {
                    item = JSON.parse(itemStr);
                    this[this.hash(key)] = item;
                    this.keys.push(key);
                    ++this.size;
                }
            } catch (e) {
                console.log(e);
            }
        }
    }
    return item === undefined ? undefined : item.value;
};

Map.prototype.put = function(key, value) {
    var hash = this.hash(key);

    if(this[hash] === undefined) {
        var item = { key : key, value : value };
        this[hash] = item;

        this.link(item);
        ++this.size;
    }
    else this[hash].value = value;
    if (this.storageId) {
        this.keys.push(key);
        try {
            localStorage.setItem(this.storageId + key, JSON.stringify(this[hash]));
        } catch (e) {
            console.log(e);
        }
    }
    return this;
};

Map.prototype.remove = function(key) {
    var hash = this.hash(key);
    var item = this[hash];
    if(item !== undefined) {
        --this.size;
        this.unlink(item);

        delete this[hash];
    }
    if (this.storageId) {
        try {
            localStorage.setItem(this.storageId + key, undefined);
        } catch (e) {
            console.log(e);
        }
    }
    return this;
};

// only works if linked
Map.prototype.removeAll = function() {
    if (this.storageId) {
        for (var i=0; i<this.keys.length; i++) {
            this.remove(this.keys[i]);
        }
        this.keys.length = 0;
    } else {
        while(this.size)
            this.remove(this.key());
    }
    return this;
};

// --- linked list helper functions

Map.prototype.link = function(item) {
    if (this.storageId) {
        return;
    }
    if(this.size == 0) {
        item.prev = item;
        item.next = item;
        this.current = item;
    }
    else {
        item.prev = this.current.prev;
        item.prev.next = item;
        item.next = this.current;
        this.current.prev = item;
    }
};

Map.prototype.unlink = function(item) {
    if (this.storageId) {
        return;
    }
    if(this.size == 0)
        this.current = undefined;
    else {
        item.prev.next = item.next;
        item.next.prev = item.prev;
        if(item === this.current)
            this.current = item.next;
    }
};

// --- iterator functions - only work if map is linked

Map.prototype.next = function() {
    this.current = this.current.next;
};

Map.prototype.key = function() {
    if (this.storageId) {
        return undefined;
    } else {
        return this.current.key;
    }
};

Map.prototype.value = function() {
    if (this.storageId) {
        return undefined;
    }
    return this.current.value;
};

1

एक और समाधान जोड़ना: HashMap मैं जावा से जावास्क्रिप्ट में पहली श्रेणी में बहुत अधिक है। आप कह सकते हैं कि बहुत अधिक ओवरहेड है, लेकिन कार्यान्वयन जावा के कार्यान्वयन के बराबर लगभग 100% है और इसमें सभी इंटरफेस और उपवर्ग शामिल हैं।

इस परियोजना को यहां पाया जा सकता है: https://github.com/Airblader/jsava मैं HashMap वर्ग के लिए (वर्तमान) स्रोत कोड भी संलग्न करूंगा, लेकिन जैसा कि कहा गया है कि यह सुपर क्लास आदि पर निर्भर करता है। qooxdoo है।

संपादित करें: कृपया ध्यान दें कि यह कोड पहले ही आउट-डेटेड है और वर्तमान कार्य के लिए गिटब प्रोजेक्ट को संदर्भित करता है। इसे लिखने के रूप में, एक ArrayListकार्यान्वयन भी है।

qx.Class.define( 'jsava.util.HashMap', {
    extend: jsava.util.AbstractMap,
    implement: [jsava.util.Map, jsava.io.Serializable, jsava.lang.Cloneable],

    construct: function () {
        var args = Array.prototype.slice.call( arguments ),
            initialCapacity = this.self( arguments ).DEFAULT_INITIAL_CAPACITY,
            loadFactor = this.self( arguments ).DEFAULT_LOAD_FACTOR;

        switch( args.length ) {
            case 1:
                if( qx.Class.implementsInterface( args[0], jsava.util.Map ) ) {
                    initialCapacity = Math.max( ((args[0].size() / this.self( arguments ).DEFAULT_LOAD_FACTOR) | 0) + 1,
                        this.self( arguments ).DEFAULT_INITIAL_CAPACITY );
                    loadFactor = this.self( arguments ).DEFAULT_LOAD_FACTOR;
                } else {
                    initialCapacity = args[0];
                }
                break;
            case 2:
                initialCapacity = args[0];
                loadFactor = args[1];
                break;
        }

        if( initialCapacity < 0 ) {
            throw new jsava.lang.IllegalArgumentException( 'Illegal initial capacity: ' + initialCapacity );
        }
        if( initialCapacity > this.self( arguments ).MAXIMUM_CAPACITY ) {
            initialCapacity = this.self( arguments ).MAXIMUM_CAPACITY;
        }
        if( loadFactor <= 0 || isNaN( loadFactor ) ) {
            throw new jsava.lang.IllegalArgumentException( 'Illegal load factor: ' + loadFactor );
        }

        var capacity = 1;
        while( capacity < initialCapacity ) {
            capacity <<= 1;
        }

        this._loadFactor = loadFactor;
        this._threshold = (capacity * loadFactor) | 0;
        this._table = jsava.JsavaUtils.emptyArrayOfGivenSize( capacity, null );
        this._init();
    },

    statics: {
        serialVersionUID: 1,

        DEFAULT_INITIAL_CAPACITY: 16,
        MAXIMUM_CAPACITY: 1 << 30,
        DEFAULT_LOAD_FACTOR: 0.75,

        _hash: function (hash) {
            hash ^= (hash >>> 20) ^ (hash >>> 12);
            return hash ^ (hash >>> 7) ^ (hash >>> 4);
        },

        _indexFor: function (hashCode, length) {
            return hashCode & (length - 1);
        },

        Entry: qx.Class.define( 'jsava.util.HashMap.Entry', {
            extend: jsava.lang.Object,
            implement: [jsava.util.Map.Entry],

            construct: function (hash, key, value, nextEntry) {
                this._value = value;
                this._next = nextEntry;
                this._key = key;
                this._hash = hash;
            },

            members: {
                _key: null,
                _value: null,
                /** @type jsava.util.HashMap.Entry */
                _next: null,
                /** @type Number */
                _hash: 0,

                getKey: function () {
                    return this._key;
                },

                getValue: function () {
                    return this._value;
                },

                setValue: function (newValue) {
                    var oldValue = this._value;
                    this._value = newValue;
                    return oldValue;
                },

                equals: function (obj) {
                    if( obj === null || !qx.Class.implementsInterface( obj, jsava.util.HashMap.Entry ) ) {
                        return false;
                    }

                    /** @type jsava.util.HashMap.Entry */
                    var entry = obj,
                        key1 = this.getKey(),
                        key2 = entry.getKey();
                    if( key1 === key2 || (key1 !== null && key1.equals( key2 )) ) {
                        var value1 = this.getValue(),
                            value2 = entry.getValue();
                        if( value1 === value2 || (value1 !== null && value1.equals( value2 )) ) {
                            return true;
                        }
                    }

                    return false;
                },

                hashCode: function () {
                    return (this._key === null ? 0 : this._key.hashCode()) ^
                        (this._value === null ? 0 : this._value.hashCode());
                },

                toString: function () {
                    return this.getKey() + '=' + this.getValue();
                },

                /**
                 * This method is invoked whenever the value in an entry is
                 * overwritten by an invocation of put(k,v) for a key k that's already
                 * in the HashMap.
                 */
                _recordAccess: function (map) {
                },

                /**
                 * This method is invoked whenever the entry is
                 * removed from the table.
                 */
                _recordRemoval: function (map) {
                }
            }
        } )
    },

    members: {
        /** @type jsava.util.HashMap.Entry[] */
        _table: null,
        /** @type Number */
        _size: 0,
        /** @type Number */
        _threshold: 0,
        /** @type Number */
        _loadFactor: 0,
        /** @type Number */
        _modCount: 0,
        /** @implements jsava.util.Set */
        __entrySet: null,

        /**
         * Initialization hook for subclasses. This method is called
         * in all constructors and pseudo-constructors (clone, readObject)
         * after HashMap has been initialized but before any entries have
         * been inserted.  (In the absence of this method, readObject would
         * require explicit knowledge of subclasses.)
         */
        _init: function () {
        },

        size: function () {
            return this._size;
        },

        isEmpty: function () {
            return this._size === 0;
        },

        get: function (key) {
            if( key === null ) {
                return this.__getForNullKey();
            }

            var hash = this.self( arguments )._hash( key.hashCode() );
            for( var entry = this._table[this.self( arguments )._indexFor( hash, this._table.length )];
                 entry !== null; entry = entry._next ) {
                /** @type jsava.lang.Object */
                var k;
                if( entry._hash === hash && ((k = entry._key) === key || key.equals( k )) ) {
                    return entry._value;
                }
            }

            return null;
        },

        __getForNullKey: function () {
            for( var entry = this._table[0]; entry !== null; entry = entry._next ) {
                if( entry._key === null ) {
                    return entry._value;
                }
            }

            return null;
        },

        containsKey: function (key) {
            return this._getEntry( key ) !== null;
        },

        _getEntry: function (key) {
            var hash = (key === null) ? 0 : this.self( arguments )._hash( key.hashCode() );
            for( var entry = this._table[this.self( arguments )._indexFor( hash, this._table.length )];
                 entry !== null; entry = entry._next ) {
                /** @type jsava.lang.Object */
                var k;
                if( entry._hash === hash
                    && ( ( k = entry._key ) === key || ( key !== null && key.equals( k ) ) ) ) {
                    return entry;
                }
            }

            return null;
        },

        put: function (key, value) {
            if( key === null ) {
                return this.__putForNullKey( value );
            }

            var hash = this.self( arguments )._hash( key.hashCode() ),
                i = this.self( arguments )._indexFor( hash, this._table.length );
            for( var entry = this._table[i]; entry !== null; entry = entry._next ) {
                /** @type jsava.lang.Object */
                var k;
                if( entry._hash === hash && ( (k = entry._key) === key || key.equals( k ) ) ) {
                    var oldValue = entry._value;
                    entry._value = value;
                    entry._recordAccess( this );
                    return oldValue;
                }
            }

            this._modCount++;
            this._addEntry( hash, key, value, i );
            return null;
        },

        __putForNullKey: function (value) {
            for( var entry = this._table[0]; entry !== null; entry = entry._next ) {
                if( entry._key === null ) {
                    var oldValue = entry._value;
                    entry._value = value;
                    entry._recordAccess( this );
                    return oldValue;
                }
            }

            this._modCount++;
            this._addEntry( 0, null, value, 0 );
            return null;
        },

        __putForCreate: function (key, value) {
            var hash = (key === null) ? 0 : this.self( arguments )._hash( key.hashCode() ),
                i = this.self( arguments )._indexFor( hash, this._table.length );
            for( var entry = this._table[i]; entry !== null; entry = entry._next ) {
                /** @type jsava.lang.Object */
                var k;
                if( entry._hash === hash
                    && ( (k = entry._key) === key || ( key !== null && key.equals( k ) ) ) ) {
                    entry._value = value;
                    return;
                }
            }

            this._createEntry( hash, key, value, i );
        },

        __putAllForCreate: function (map) {
            var iterator = map.entrySet().iterator();
            while( iterator.hasNext() ) {
                var entry = iterator.next();
                this.__putForCreate( entry.getKey(), entry.getValue() );
            }
        },

        _resize: function (newCapacity) {
            var oldTable = this._table,
                oldCapacity = oldTable.length;
            if( oldCapacity === this.self( arguments ).MAXIMUM_CAPACITY ) {
                this._threshold = Number.MAX_VALUE;
                return;
            }

            var newTable = jsava.JsavaUtils.emptyArrayOfGivenSize( newCapacity, null );
            this._transfer( newTable );
            this._table = newTable;
            this._threshold = (newCapacity * this._loadFactor) | 0;
        },

        _transfer: function (newTable) {
            var src = this._table,
                newCapacity = newTable.length;
            for( var j = 0; j < src.length; j++ ) {
                var entry = src[j];
                if( entry !== null ) {
                    src[j] = null;
                    do {
                        var next = entry._next,
                            i = this.self( arguments )._indexFor( entry._hash, newCapacity );
                        entry._next = newTable[i];
                        newTable[i] = entry;
                        entry = next;
                    } while( entry !== null );
                }
            }
        },

        putAll: function (map) {
            var numKeyToBeAdded = map.size();
            if( numKeyToBeAdded === 0 ) {
                return;
            }

            if( numKeyToBeAdded > this._threshold ) {
                var targetCapacity = (numKeyToBeAdded / this._loadFactor + 1) | 0;
                if( targetCapacity > this.self( arguments ).MAXIMUM_CAPACITY ) {
                    targetCapacity = this.self( arguments ).MAXIMUM_CAPACITY;
                }

                var newCapacity = this._table.length;
                while( newCapacity < targetCapacity ) {
                    newCapacity <<= 1;
                }
                if( newCapacity > this._table.length ) {
                    this._resize( newCapacity );
                }
            }

            var iterator = map.entrySet().iterator();
            while( iterator.hasNext() ) {
                var entry = iterator.next();
                this.put( entry.getKey(), entry.getValue() );
            }
        },

        remove: function (key) {
            var entry = this._removeEntryForKey( key );
            return entry === null ? null : entry._value;
        },

        _removeEntryForKey: function (key) {
            var hash = (key === null) ? 0 : this.self( arguments )._hash( key.hashCode() ),
                i = this.self( arguments )._indexFor( hash, this._table.length ),
                prev = this._table[i],
                entry = prev;

            while( entry !== null ) {
                var next = entry._next,
                    /** @type jsava.lang.Object */
                        k;
                if( entry._hash === hash
                    && ( (k = entry._key) === key || ( key !== null && key.equals( k ) ) ) ) {
                    this._modCount++;
                    this._size--;
                    if( prev === entry ) {
                        this._table[i] = next;
                    } else {
                        prev._next = next;
                    }
                    entry._recordRemoval( this );
                    return entry;
                }
                prev = entry;
                entry = next;
            }

            return entry;
        },

        _removeMapping: function (obj) {
            if( obj === null || !qx.Class.implementsInterface( obj, jsava.util.Map.Entry ) ) {
                return null;
            }

            /** @implements jsava.util.Map.Entry */
            var entry = obj,
                key = entry.getKey(),
                hash = (key === null) ? 0 : this.self( arguments )._hash( key.hashCode() ),
                i = this.self( arguments )._indexFor( hash, this._table.length ),
                prev = this._table[i],
                e = prev;

            while( e !== null ) {
                var next = e._next;
                if( e._hash === hash && e.equals( entry ) ) {
                    this._modCount++;
                    this._size--;
                    if( prev === e ) {
                        this._table[i] = next;
                    } else {
                        prev._next = next;
                    }
                    e._recordRemoval( this );
                    return e;
                }
                prev = e;
                e = next;
            }

            return e;
        },

        clear: function () {
            this._modCount++;
            var table = this._table;
            for( var i = 0; i < table.length; i++ ) {
                table[i] = null;
            }
            this._size = 0;
        },

        containsValue: function (value) {
            if( value === null ) {
                return this.__containsNullValue();
            }

            var table = this._table;
            for( var i = 0; i < table.length; i++ ) {
                for( var entry = table[i]; entry !== null; entry = entry._next ) {
                    if( value.equals( entry._value ) ) {
                        return true;
                    }
                }
            }

            return false;
        },

        __containsNullValue: function () {
            var table = this._table;
            for( var i = 0; i < table.length; i++ ) {
                for( var entry = table[i]; entry !== null; entry = entry._next ) {
                    if( entry._value === null ) {
                        return true;
                    }
                }
            }

            return false;
        },

        clone: function () {
            /** @type jsava.util.HashMap */
            var result = null;
            try {
                result = this.base( arguments );
            } catch( e ) {
                if( !qx.Class.isSubClassOf( e.constructor, jsava.lang.CloneNotSupportedException ) ) {
                    throw e;
                }
            }

            result._table = jsava.JsavaUtils.emptyArrayOfGivenSize( this._table.length, null );
            result.__entrySet = null;
            result._modCount = 0;
            result._size = 0;
            result._init();
            result.__putAllForCreate( this );

            return result;
        },

        _addEntry: function (hash, key, value, bucketIndex) {
            var entry = this._table[bucketIndex];
            this._table[bucketIndex] = new (this.self( arguments ).Entry)( hash, key, value, entry );
            if( this._size++ >= this._threshold ) {
                this._resize( 2 * this._table.length );
            }
        },

        _createEntry: function (hash, key, value, bucketIndex) {
            var entry = this._table[bucketIndex];
            this._table[bucketIndex] = new (this.self( arguments ).Entry)( hash, key, value, entry );
            this._size++;
        },

        keySet: function () {
            var keySet = this._keySet;
            return keySet !== null ? keySet : ( this._keySet = new this.KeySet( this ) );
        },

        values: function () {
            var values = this._values;
            return values !== null ? values : ( this._values = new this.Values( this ) );
        },

        entrySet: function () {
            return this.__entrySet0();
        },

        __entrySet0: function () {
            var entrySet = this.__entrySet;
            return entrySet !== null ? entrySet : ( this.__entrySet = new this.EntrySet( this ) );
        },

        /** @private */
        HashIterator: qx.Class.define( 'jsava.util.HashMap.HashIterator', {
            extend: jsava.lang.Object,
            implement: [jsava.util.Iterator],

            type: 'abstract',

            /** @protected */
            construct: function (thisHashMap) {
                this.__thisHashMap = thisHashMap;
                this._expectedModCount = this.__thisHashMap._modCount;
                if( this.__thisHashMap._size > 0 ) {
                    var table = this.__thisHashMap._table;
                    while( this._index < table.length && ( this._next = table[this._index++] ) === null ) {
                        // do nothing
                    }
                }
            },

            members: {
                __thisHashMap: null,

                /** @type jsava.util.HashMap.Entry */
                _next: null,
                /** @type Number */
                _expectedModCount: 0,
                /** @type Number */
                _index: 0,
                /** @type jsava.util.HashMap.Entry */
                _current: null,

                hasNext: function () {
                    return this._next !== null;
                },

                _nextEntry: function () {
                    if( this.__thisHashMap._modCount !== this._expectedModCount ) {
                        throw new jsava.lang.ConcurrentModificationException();
                    }

                    var entry = this._next;
                    if( entry === null ) {
                        throw new jsava.lang.NoSuchElementException();
                    }

                    if( (this._next = entry._next) === null ) {
                        var table = this.__thisHashMap._table;
                        while( this._index < table.length && ( this._next = table[this._index++] ) === null ) {
                            // do nothing
                        }
                    }

                    this._current = entry;
                    return entry;
                },

                remove: function () {
                    if( this._current === null ) {
                        throw new jsava.lang.IllegalStateException();
                    }

                    if( this.__thisHashMap._modCount !== this._expectedModCount ) {
                        throw new jsava.lang.ConcurrentModificationException();
                    }

                    var key = this._current._key;
                    this._current = null;
                    this.__thisHashMap._removeEntryForKey( key );
                    this._expectedModCount = this.__thisHashMap._modCount;
                }
            }
        } ),

        _newKeyIterator: function () {
            return new this.KeyIterator( this );
        },

        _newValueIterator: function () {
            return new this.ValueIterator( this );
        },

        _newEntryIterator: function () {
            return new this.EntryIterator( this );
        },

        /** @private */
        ValueIterator: qx.Class.define( 'jsava.util.HashMap.ValueIterator', {
            extend: jsava.util.HashMap.HashIterator,

            construct: function (thisHashMap) {
                this.base( arguments, thisHashMap );
            },

            members: {
                next: function () {
                    return this._nextEntry()._value;
                }
            }
        } ),

        /** @private */
        KeyIterator: qx.Class.define( 'jsava.util.HashMap.KeyIterator', {
            extend: jsava.util.HashMap.HashIterator,

            construct: function (thisHashMap) {
                this.base( arguments, thisHashMap );
            },

            members: {
                next: function () {
                    return this._nextEntry().getKey();
                }
            }
        } ),

        /** @private */
        EntryIterator: qx.Class.define( 'jsava.util.HashMap.EntryIterator', {
            extend: jsava.util.HashMap.HashIterator,

            construct: function (thisHashMap) {
                this.base( arguments, thisHashMap );
            },

            members: {
                next: function () {
                    return this._nextEntry();
                }
            }
        } ),

        /** @private */
        KeySet: qx.Class.define( 'jsava.util.HashMap.KeySet', {
            extend: jsava.util.AbstractSet,

            construct: function (thisHashMap) {
                this.base( arguments );
                this.__thisHashMap = thisHashMap;
            },

            members: {
                __thisHashMap: null,

                iterator: function () {
                    return this.__thisHashMap._newKeyIterator();
                },

                size: function () {
                    return this.__thisHashMap._size;
                },

                contains: function (obj) {
                    return this.__thisHashMap.containsKey( obj );
                },

                remove: function (obj) {
                    return this.__thisHashMap._removeEntryForKey( obj ) !== null;
                },

                clear: function () {
                    this.__thisHashMap.clear();
                }
            }
        } ),

        /** @private */
        Values: qx.Class.define( 'jsava.util.HashMap.Values', {
            extend: jsava.util.AbstractCollection,

            construct: function (thisHashMap) {
                this.base( arguments );
                this.__thisHashMap = thisHashMap;
            },

            members: {
                __thisHashMap: null,

                iterator: function () {
                    return this.__thisHashMap._newValueIterator();
                },

                size: function () {
                    return this.__thisHashMap._size;
                },

                contains: function (obj) {
                    return this.__thisHashMap.containsValue( obj );
                },

                clear: function () {
                    this.__thisHashMap.clear();
                }
            }
        } ),

        /** @private */
        EntrySet: qx.Class.define( 'jsava.util.HashMap.EntrySet', {
            extend: jsava.util.AbstractSet,

            construct: function (thisHashMap) {
                this.base( arguments );
                this.__thisHashMap = thisHashMap;
            },

            members: {
                __thisHashMap: null,

                iterator: function () {
                    return this.__thisHashMap._newEntryIterator();
                },

                size: function () {
                    return this.__thisHashMap._size;
                },

                contains: function (obj) {
                    if( obj === null || !qx.Class.implementsInterface( obj, jsava.util.Map.Entry ) ) {
                        return false;
                    }

                    /** @implements jsava.util.Map.Entry */
                    var entry = obj,
                        candidate = this.__thisHashMap._getEntry( entry.getKey() );
                    return candidate !== null && candidate.equals( entry );
                },

                remove: function (obj) {
                    return this.__thisHashMap._removeMapping( obj ) !== null;
                },

                clear: function () {
                    this.__thisHashMap.clear();
                }
            }
        } )
    }
} );

हम्म दिलचस्प दृष्टिकोण .. क्या आपने एक स्वचालित दृष्टिकोण की कोशिश करने पर विचार किया है? वर्तमान जावा कार्यान्वयन के लिए स्रोत कोड पर जावा-टू-जावास्क्रिप्ट कम्पाइलर चल रहा है?
क्लाउडीयू

नहींं :) यह मेरे लिए एक मजेदार परियोजना है और काफी कुछ चीजें थीं जो मैं बस "कॉपी" कोड नहीं कर सकता था। मुझे जावा-टू-जावास्क्रिप्ट कम्पाइलर के बारे में पता नहीं है, हालांकि मुझे विश्वास है कि वे मौजूद हैं। मुझे यकीन नहीं है कि वे इसका कितना अच्छा अनुवाद करेंगे। मुझे पूरा यकीन है कि वे किसी भी मामले में अच्छी गुणवत्ता वाले कोड का उत्पादन नहीं करेंगे, हालांकि।
इंगो बुर्क

आह गच्चा। मैं Google वेब टूलकिट के कंपाइलर के बारे में सोच रहा था , लेकिन ऐसा लगता है कि उन्होंने कोर लाइब्रेरीज़ के लिए आप यहाँ क्या कर रहे हैं: "GWT कंपाइलर जावा भाषा के विशाल बहुमत का समर्थन करता है। GWT रनटाइम लाइब्रेरी एक प्रासंगिक उपसमूह का अनुकरण करता है। जावा रनटाइम लाइब्रेरी। " शायद कुछ देखने के लिए कि दूसरों ने उसी समस्या को कैसे हल किया!
क्लॉडिउ

हाँ। मुझे यकीन है कि Google का समाधान मेरे से बहुत परे है, लेकिन फिर, मुझे बस कुछ मज़ा आ रहा है। दुर्भाग्य से, स्रोत कोड को रद्द कर दिया गया लगता है (?), कम से कम मैं इसे ब्राउज़ नहीं कर सकता और दिलचस्प लिंक मृत लग रहे हैं। बहुत बुरा, मैं इसे देखने के लिए प्यार होता।
इंगो बुर्क

चारों ओर खेल कर मज़ा लेना सीखने का सबसे अच्छा तरीका है =)। साझा करने के लिए धन्यवाद
21:39

0

फिर भी मेरे द्वारा एक और नक्शा कार्यान्वयन। रैंडमाइज़र के साथ, 'जेनरिक' और 'इटरेटर' =)

var HashMap = function (TKey, TValue) {
    var db = [];
    var keyType, valueType;

    (function () {
        keyType = TKey;
        valueType = TValue;
    })();

    var getIndexOfKey = function (key) {
        if (typeof key !== keyType)
            throw new Error('Type of key should be ' + keyType);
        for (var i = 0; i < db.length; i++) {
            if (db[i][0] == key)
                return i;
        }
        return -1;
    }

    this.add = function (key, value) {
        if (typeof key !== keyType) {
            throw new Error('Type of key should be ' + keyType);
        } else if (typeof value !== valueType) {
            throw new Error('Type of value should be ' + valueType);
        }
        var index = getIndexOfKey(key);
        if (index === -1)
            db.push([key, value]);
        else
            db[index][1] = value;
        return this;
    }

    this.get = function (key) {
        if (typeof key !== keyType || db.length === 0)
            return null;
        for (var i = 0; i < db.length; i++) {
            if (db[i][0] == key)
                return db[i][1];
        }
        return null;
    }

    this.size = function () {
        return db.length;
    }

    this.keys = function () {
        if (db.length === 0)
            return [];
        var result = [];
        for (var i = 0; i < db.length; i++) {
            result.push(db[i][0]);
        }
        return result;
    }

    this.values = function () {
        if (db.length === 0)
            return [];
        var result = [];
        for (var i = 0; i < db.length; i++) {
            result.push(db[i][1]);
        }
        return result;
    }

    this.randomize = function () {
        if (db.length === 0)
            return this;
        var currentIndex = db.length, temporaryValue, randomIndex;
        while (0 !== currentIndex) {
            randomIndex = Math.floor(Math.random() * currentIndex);
            currentIndex--;
            temporaryValue = db[currentIndex];
            db[currentIndex] = db[randomIndex];
            db[randomIndex] = temporaryValue;
        }
        return this;
    }

    this.iterate = function (callback) {
        if (db.length === 0)
            return false;
        for (var i = 0; i < db.length; i++) {
            callback(db[i][0], db[i][1]);
        }
        return true;
    }
}

उदाहरण:

var a = new HashMap("string", "number");
a.add('test', 1132)
 .add('test14', 666)
 .add('1421test14', 12312666)
 .iterate(function (key, value) {console.log('a['+key+']='+value)});
/*
a[test]=1132
a[test14]=666
a[1421test14]=12312666 
*/
a.randomize();
/*
a[1421test14]=12312666
a[test]=1132
a[test14]=666
*/
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.