क्या जावास्क्रिप्ट में किसी प्रकार का हैश कोड फ़ंक्शन है?


150

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

set[obj] = true;

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


32
एक ही मूल्य के लिए सभी 'हैश' वस्तुओं का कारण यह है कि आपने उनके स्टर्लिंग तरीकों को ओवरराइड नहीं किया है। चूँकि कुंजी को स्ट्रिंग्स होना आवश्यक है, इसलिए स्टर्लिंग विधि को स्वचालित रूप से एक वैध कुंजी प्राप्त करने के लिए कहा जाता है, इसलिए आपकी सभी वस्तुएँ एक ही डिफ़ॉल्ट स्ट्रिंग में परिवर्तित हो रही हैं: "[ऑब्जेक्ट ऑब्जेक्ट]"।
अलैनिंग

4
JSON.stringify(obj)या obj.toSource()समस्या और लक्ष्य प्लेटफ़ॉर्म के आधार पर आपके लिए काम कर सकता है।
अन्नपूर्णे

4
@Annan JSON.stringify (obj) का शाब्दिक अर्थ केवल (पूरी) वस्तु को एक स्ट्रिंग में बदलना है। तो आप मूल रूप से सिर्फ ऑब्जेक्ट को खुद पर कॉपी करेंगे। यह व्यर्थ है, अंतरिक्ष की बर्बादी है और इष्टतम नहीं है।
मेटलस्टॉर्म

1
@Metalstorm सच है, यही वजह है कि यह निर्भर करता है कि आपकी समस्या क्या है। जब मुझे यह प्रश्न Google के माध्यम से मिला तो मेरा अंतिम समाधान वस्तुओं पर toSource () को कॉल कर रहा था। एक अन्य तरीका सिर्फ स्रोत पर एक पारंपरिक हैश का उपयोग करना होगा।
अन्ननफ़ेय

@ अयनन, toSourceक्रोम btw में काम नहीं करते
Pacerier

जवाबों:


35

जावास्क्रिप्ट ऑब्जेक्ट केवल कुंजी के रूप में स्ट्रिंग्स का उपयोग कर सकते हैं (कुछ भी स्ट्रिंग में परिवर्तित हो जाता है)।

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

var ObjectReference = [];
ObjectReference.push(obj);

set['ObjectReference.' + ObjectReference.indexOf(obj)] = true;

जाहिर है यह थोड़ी सी क्रिया है, लेकिन आप कुछ तरीके लिख सकते हैं जो इसे संभालते हैं और सभी विली निली को प्राप्त करते हैं और सेट करते हैं।

संपादित करें:

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

यह एक और दिलचस्प बिंदु लाता है; आप जिन वस्तुओं को हैश करना चाहते हैं उन पर एक toString विधि को परिभाषित कर सकते हैं, और जो उनके हैश पहचानकर्ता का निर्माण कर सकते हैं।


एक अन्य विकल्प यह होगा कि प्रत्येक वस्तु को एक यादृच्छिक मान दिया जाए - शायद एक यादृच्छिक संख्या + कुल टिक्स - फिर सरणी से ऑब्जेक्ट को जोड़ने / हटाने के लिए फ़ंक्शन का एक सेट होता है।
सुगेन्द्रन

4
यदि आप एक ही ऑब्जेक्ट को दो बार जोड़ते हैं तो यह विफल हो जाएगा। यह सोचेंगे कि यह अलग है।
डैनियल एक्स मूर

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

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

35
वस्तुओं को हैशिंग करने की बात क्या है अगर हर बार जब आप उन्हें संदर्भित करते हैं तो आपको एक सरणी के रैखिक स्कैन की आवश्यकता होती है?
बॉरदॉर्गल

57

यदि आप एक हैशकोड () जावास्क्रिप्ट में जावा की तरह कार्य करना चाहते हैं, तो वह आपका है:

String.prototype.hashCode = function(){
    var hash = 0;
    for (var i = 0; i < this.length; i++) {
        var character = this.charCodeAt(i);
        hash = ((hash<<5)-hash)+character;
        hash = hash & hash; // Convert to 32bit integer
    }
    return hash;
}

यह जावा (बिटकॉइन ऑपरेटर) में कार्यान्वयन का तरीका है।

कृपया ध्यान दें कि हैशकोड सकारात्मक और नकारात्मक हो सकता है, और यह सामान्य है, देखें हाशकोड नकारात्मक मूल्य दे रहा है । इसलिए, आप Math.abs()इस फ़ंक्शन के साथ उपयोग करने पर विचार कर सकते हैं ।


5
इस -hash, नहीं सही बनाता है
qodeninja

2
@ किमखा charजेएस में आरक्षित शब्द है और इससे कुछ समस्याएं हो सकती हैं। कोई और नाम बेहतर होगा।
szeryf

16
@qodeninja कौन कहता है? ऐसा दावा मैंने पहली बार सुना है। क्या आप किसी स्रोत से लिंक कर सकते हैं? हेज़ की गणना आमतौर पर निश्चित आकार के पूर्णांक अंकगणितीय और बिट संचालन का उपयोग करके की जाती है, इसलिए सकारात्मक या नकारात्मक परिणाम प्राप्त करना अपेक्षित है।
szeryf

7
पिकी, लेकिन ... "अगर (यह। गति == 0) वापसी हैश?" बेमानी है :) और व्यक्तिगत रूप से "चरित्र" को "कोड" में बदल देगा।
मेटलस्टॉर्म

10
@qodeninja और @ szeryf: आपको बस सावधान रहना होगा कि आप इसका उपयोग कैसे करते हैं। उदाहरण के लिए, मैंने 20 तत्वों के साथ pickOne["helloo".hashCode() % 20]एक सरणी के लिए करने की कोशिश की pickOne। मुझे undefinedइसलिए मिला क्योंकि हैश कोड नकारात्मक है, इसलिए यह एक उदाहरण है जिसमें किसी ने (मुझे) स्पष्ट रूप से सकारात्मक हैश कोड माना है।
जिम पीवार्स्की

31

ऐसा करने का सबसे आसान तरीका है कि आप अपनी प्रत्येक वस्तु को अपनी अनूठी toStringविधि दें:

(function() {
    var id = 0;

    /*global MyObject */
    MyObject = function() {
        this.objectId = '<#MyObject:' + (id++) + '>';
        this.toString= function() {
            return this.objectId;
        };
    };
})();

मेरे पास एक ही समस्या थी और इसने मेरे लिए न्यूनतम उपद्रव के साथ पूरी तरह से हल कर दिया, और बहुत आसान था कि कुछ फैटी जावा शैली को फिर से लागू करना और अपने ऑब्जेक्ट कक्षाओं में Hashtableजोड़ना equals()और जोड़ना hashCode()। बस यह सुनिश्चित करें कि आप एक स्ट्रिंग '<#MyObject: 12> को अपने हैश में न रखें या यह उस आईडी के साथ आपकी बाहर निकलने वाली वस्तु के लिए प्रवेश को मिटा देगा।

अब मेरे सभी हैश पूरी तरह से सर्द हैं। मैंने इस सटीक विषय के बारे में कुछ दिन पहले ही एक ब्लॉग प्रविष्टि भी पोस्ट की थी ।


28
लेकिन यह पूरी बात याद आती है। जावा है equals()और hashCode()इतना है कि दो बराबर वस्तुओं एक ही हैश मान की है। उपरोक्त विधि का उपयोग करने का अर्थ है कि प्रत्येक उदाहरण में MyObjectएक अद्वितीय स्ट्रिंग होगी, जिसका अर्थ है कि आपको उस ऑब्जेक्ट का एक संदर्भ रखना होगा जो कभी भी मानचित्र से सही मान प्राप्त कर सके। चाबी का होना निरर्थक है, क्योंकि इसका किसी वस्तु की विशिष्टता से कोई लेना-देना नहीं है। toString()कुंजी के रूप में आप जिस विशिष्ट प्रकार की वस्तु का उपयोग कर रहे हैं, उसके लिए एक उपयोगी फ़ंक्शन को लागू करना होगा।
सेथरो

@ सेस्त्रो आप toStringवस्तुओं के लिए इस तरह से लागू कर सकते हैं कि यह सीधे एक समतुल्य संबंध के लिए मैप करता है ताकि दो ऑब्जेक्ट एक ही स्ट्रिंग इफ़ का निर्माण करें जो उन्हें "बराबर" माना जाता है।
डैनियल एक्स मूर

3
सही है, और इसका उपयोग करने का एकमात्र सही तरीका toString()है कि आप Objectए के रूप में उपयोग कर सकें Set। मुझे लगता है कि मैंने आपके उत्तर को गलत समझा है क्योंकि मामले के आधार पर या किसी मामले के toString()बराबर लिखने से बचने के लिए एक सामान्य समाधान प्रदान करने की कोशिश कर रहा हूं । equals()hashCode()
सेथरो

3
Dowvoted। यह एक हैशकोड नहीं है, मेरे जवाब देखें: stackoverflow.com/a/14953738/524126 और
हैशकोड

5
@Metalstorm सवाल "सच" हैशकोड के बारे में नहीं पूछ रहा था, बल्कि यह कि जावास्क्रिप्ट में एक सेट के रूप में किसी ऑब्जेक्ट का सफलतापूर्वक उपयोग कैसे करें।
डैनियल एक्स मूर

20

आपने जो वर्णन किया है वह हार्मोनी वीकेमैप्स द्वारा कवर किया गया है , जो ECMAScript 6 विनिर्देशन (जावास्क्रिप्ट का अगला संस्करण) का हिस्सा है। वह है: एक ऐसा सेट जहाँ कुंजियाँ कुछ भी हो सकती हैं (अपरिभाषित सहित) और गैर-एन्यूमरेबल है।

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

से MDN :

var wm1 = new WeakMap(),
    wm2 = 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').

wm1.has(o1);   // True
wm1.delete(o1);
wm1.has(o1);   // False

WeakMaps वर्तमान फ़ायरफ़ॉक्स, क्रोम और एज में उपलब्ध हैं। वे Node v7 में भी समर्थित हैं, और --harmony-weak-mapsध्वज के साथ v6 में ।


1
इन और में क्या अंतर है Map?
smac89

@ smac89 WeakMap की सीमाएँ हैं: 1) केवल ऑब्जेक्ट्स को कुंजी 2 के रूप में लेता है) कोई आकार गुण 3) कोई पुनरावृत्ति या फॉरच विधि 4) कोई स्पष्ट विधि नहीं है। कुंजी ऑब्जेक्ट है - इसलिए जब ऑब्जेक्ट मेमोरी से हटा दिया जाएगा - इस ऑब्जेक्ट से जुड़े WeakMap के डेटा को भी हटा दिया जाएगा। यह बहुत उपयोगी है जब हम जानकारी रखना चाहते हैं, जो कि वस्तु के मौजूद रहने के दौरान ही मौजूद होनी चाहिए। इसलिए वीकेप में केवल विधियाँ हैं: सेट करें, लिखने के लिए हटाएं और पढ़ें, पढ़ने के लिए हैं
एकाटेरिना टोकरेवा

यह बिल्कुल सही ढंग से काम नहीं करता है ... var m = new Map();m.set({},"abc"); console.log(m.get({}) //=>undefinedयह केवल तभी काम करता है जब आपके पास वही वैरिएबल हो जिसे आप मूल रूप से सेट कमांड में संदर्भित करते हैं। जैसेvar m = new Map();a={};m.set(a,"abc"); console.log(m.get(a) //=>undefined
संकर्ण

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

1
@ अच्छी जगह हाजिर! हालाँकि मैं अब यह जानता हूं, फिर भी मैं शायद पीछे नहीं
हटता

19

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

Function.prototype.getHashCode = (function(id) {
    return function() {
        if (!this.hashCode) {
            this.hashCode = '<hash|#' + (id++) + '>';
        }
        return this.hashCode;
    }
}(0));

7
यदि आप इस तरह से जाना चाहते हैं , तो सेट के Object.definePropertyसाथ हैशकोड सेट करना बहुत बेहतर enumerableहै false, इसलिए आप किसी भी for .. inलूप को क्रैश नहीं करेंगे ।
सेबस्टियन नोवाक

14

अपनी विशिष्ट स्थिति के लिए मैं केवल वस्तु की समानता के बारे में परवाह करता हूं जहां तक ​​किज और आदिम मूल्य चलते हैं। मेरे लिए काम करने वाला समाधान ऑब्जेक्ट को उसके JSON प्रतिनिधित्व में परिवर्तित कर रहा था और हैश के रूप में उपयोग कर रहा था। संभावित रूप से असंगत होने की कुंजी के आदेश जैसी सीमाएं हैं; लेकिन जैसा कि मैंने कहा कि यह मेरे लिए काम करता है क्योंकि इन वस्तुओं को एक ही स्थान पर उत्पन्न किया जा रहा था।

var hashtable = {};

var myObject = {a:0,b:1,c:2};

var hash = JSON.stringify(myObject);
// '{"a":0,"b":1,"c":2}'

hashtable[hash] = myObject;
// {
//   '{"a":0,"b":1,"c":2}': myObject
// }

10

मैंने एक छोटे जावास्क्रिप्ट मॉड्यूल को कुछ समय पहले तार, वस्तुओं, सरणियों, आदि के लिए हैशकोड बनाने के लिए रखा था (मैंने इसे सिर्फ GitHub :) के लिए प्रतिबद्ध किया है )

उपयोग:

Hashcode.value("stackoverflow")
// -2559914341
Hashcode.value({ 'site' : "stackoverflow" })
// -3579752159

क्या जावास्क्रिप्ट का GC सर्कुलर संदर्भों पर भी गला नहीं मारता?
क्लेटन रबेंडा

@ रयान लॉन्ग मैं कह सकता हूं कि अगर आपके पास सर्कुलर रेफरेंस हैं तो आपको अपना कोड
रिफलेक्टर

11
@Metalstorm "तो आपको अपना कोड फिर से भरना होगा" क्या आप मजाक कर रहे हैं? प्रत्येक DOM एलिमेंट पैरेंट और चाइल्ड पेयर का एक सर्कुलर रेफरेंस बनता है।
क्रिस मिडलटन

8
यह एक खराब काम करता है हैशिंग ऑब्जेक्ट्स में संख्यात्मक गुण होते हैं, कई मामलों में एक ही मूल्य लौटाते हैं, अर्थात var hash1 = Hashcode.value({ a: 1, b: 2 }); var hash2 = Hashcode.value({ a: 2, b: 1 }); console.log(hash1, hash2);लॉग करेंगे2867874173 2867874173
जूलियन बेयरुबे

9

जावास्क्रिप्ट स्पेसिफिकेशन इंडेक्स नाम पर इनस्ट्रिंग रूपांतरण प्रदर्शन के रूप में अनुक्रमित संपत्ति पहुंच को परिभाषित करता है। उदाहरण के लिए,

myObject[myProperty] = ...;

के समान है

myObject[myProperty.toString()] = ...;

यह जावास्क्रिप्ट में आवश्यक है

myObject["someProperty"]

के समान है

myObject.someProperty

और हाँ, यह मुझे दुखी भी करता है :-(


9

ECMAScript 6 में अब एक Setऐसा काम है जो आप कैसे करना चाहते हैं: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set

यह पहले से ही नवीनतम Chrome, FF और IE11 में उपलब्ध है।


1
यह 2016 में शीर्ष उत्तर होना चाहिए। यदि आप बैबेल का उपयोग करते हैं, तो आप ईएस 6 कल्पना के अनुसार सेट का उपयोग कर सकते हैं और यह ईएस 5 आउटपुट में स्वचालित रूप से पॉलीफ़िल्ड हो जाएगा। babeljs.io/docs/learn-es2015/#map-set-weak-map-weak-set
atroberts20 20

5

संदर्भ: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol

आप अद्वितीय कुंजी और पहुंच ऑब्जेक्ट बनाने के लिए Es6 प्रतीक का उपयोग कर सकते हैं। प्रतीक () से लौटाया गया प्रत्येक प्रतीक मूल्य अद्वितीय है। एक प्रतीक मूल्य का उपयोग वस्तु गुणों के लिए एक पहचानकर्ता के रूप में किया जा सकता है; यह डेटा प्रकार का एकमात्र उद्देश्य है।

var obj = {};

obj[Symbol('a')] = 'a';
obj[Symbol.for('b')] = 'b';
obj['c'] = 'c';
obj.d = 'd';

2
सिवाय इसके कि वास्तव में प्रतीक को फिर से पुनर्जीवित करने का कोई तरीका नहीं है x = Symbol ('a'); let y = Symbol ('a'); कंसोल .log (x === y); // रिटर्न फर्जी है इसलिए सिंबल हैश की तरह काम नहीं करता है।
रिचर्ड कोलेट

3

यहां मेरा सरल समाधान है जो एक अद्वितीय पूर्णांक लौटाता है।

function hashcode(obj) {
    var hc = 0;
    var chars = JSON.stringify(obj).replace(/\{|\"|\}|\:|,/g, '');
    var len = chars.length;
    for (var i = 0; i < len; i++) {
        // Bump 7 to larger prime number to increase uniqueness
        hc += (chars.charCodeAt(i) * 7);
    }
    return hc;
}

2
इस की जटिलता
हैशकोड के

मुझे यह निश्चित रूप से जटिल नहीं लगता। मैं उत्सुक था, हालांकि: क्यों बदला हुआ चरण? बहिष्करण अन्यथा charCodeAt पर ठीक लौटा होता, तो क्या वे नहीं होते?
ग्रेग पेटिट

बहुत बुरा hashcode({a:1, b:2}) === hashcode({a:2, b:1})और कई अन्य संघर्षों के कारण।
मारार्टिनस

3

शीर्षक के आधार पर, हम js के साथ मजबूत हैश उत्पन्न कर सकते हैं, इसका उपयोग किसी ऑब्जेक्ट से एक अद्वितीय हैश उत्पन्न करने के लिए किया जा सकता है, एक पैरामन्स की एक सरणी, एक स्ट्रिंग, या जो भी हो।

बाद में इसे अनुक्रमित करने के लिए किसी भी संभावित मिलान त्रुटियों से बचें, जबकि परमर्स से एक सूचकांक प्राप्त करने की अनुमति देता है (ऑब्जेक्ट को खोजने / लूप करने से बचें):

async function H(m) {
  const msgUint8 = new TextEncoder().encode(m)                       
  const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8)          
  const hashArray = Array.from(new Uint8Array(hashBuffer))                    
  const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('')
  console.log(hashHex)
}

/* Examples ----------------------- */
H("An obscure ....")
H(JSON.stringify( {"hello" : "world"} ))
H(JSON.stringify( [54,51,54,47] ))

मेरे ब्राउज़र में उपरोक्त आउटपुट, यह आपके लिए भी समान होना चाहिए ( क्या यह वास्तव में है? ):

bf1cf3fe6975fe382ab392ec1dd42009380614be03d489f23601c11413cfca2b
93a23971a914e5eacbf0a8d25154cda309c3c1c72fbb9914d47c60f3cb681588
d2f209e194045604a3b15bdfd7502898a0e848e4603c5a818bd01da69c00ad19

https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#Converting_a_digest_to_a_hex_string


1

मेरा समाधान वैश्विक Objectवस्तु के लिए एक स्थिर कार्य का परिचय देता है ।

(function() {
    var lastStorageId = 0;

    this.Object.hash = function(object) {
        var hash = object.__id;

        if (!hash)
             hash = object.__id = lastStorageId++;

        return '#' + hash;
    };
}());

मुझे लगता है कि यह जावास्क्रिप्ट में अन्य ऑब्जेक्ट हेरफेर कार्यों के साथ अधिक सुविधाजनक है।


1
समान आंतरिक मूल्यों वाली वस्तुएं हैश को अलग-अलग हैश में रखती हैं, यह वह नहीं है जो एक हैश (कोड) करता है।
मेटलस्टॉर्म

जावास्क्रिप्ट में (और मुझे लगता है कि लगभग हर दूसरी भाषा में भी) एक ही आंतरिक मूल्यों के साथ बनाई गई दो वस्तुएं अभी भी अलग-अलग ऑब्जेक्ट हैं, क्योंकि अंडरलेइंग डेटा प्रकार प्रत्येक नए ऑब्जेक्ट उदाहरण द्वारा दर्शाया गया है। jsfiddle.net/h4G9f
जॉनी

4
हां, लेकिन वह नहीं है जो एक हैशकोड है, हैशकोड का उपयोग किसी ऑब्जेक्ट राज्य की समानता की जांच के लिए किया जाता है। एक हैश की तरह, एक ही इनपुट में (वैरिएबल वैल्यूज) समान हैश निकलता है। आप जो खोज रहे हैं वह एक यूयूआईडी है (जो कि आपका कार्य प्रदान करता है)।
मेटलस्टॉर्म

1
आप सही हे। मैं प्रश्न को गलत समझता हूं। वास्तव में बुरा है, कि स्वीकृत जवाब एक अच्छा समाधान प्रदान नहीं करता है।
जॉनी

अपने कार्य को भी लेते हुए, मैं इसे इस तरह अधिक पसंद करूंगा: jsfiddle.net/xVSsd समान परिणाम, छोटा (LoC + वर्ण), और संभवत: एक छोटा सा छोटा सा तेज :)
Metalstorm

1

मैं अन्य उत्तरों की तुलना में थोड़ा गहरा जाने की कोशिश करूंगा।

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

एक समस्या हैश / हैशकोड शब्द के साथ है ... क्रिप्टोग्राफ़िक हैशिंग और नॉन-क्रिप्टोग्राफ़िक हैशिंग है। दूसरी समस्या, क्या आपको यह समझना होगा कि हैशिंग क्यों उपयोगी है और यह कैसे काम करता है।

जब हम जावास्क्रिप्ट या जावा में हैशिंग के बारे में बात करते हैं, तो अधिकांश समय हम गैर-क्रिप्टोग्राफिक हैशिंग के बारे में बात कर रहे हैं, आमतौर पर हैशमैप / हैशटेबल के लिए हैशिंग के बारे में (जब तक कि हम प्रमाणीकरण या पासवर्ड पर काम नहीं कर रहे हैं, जो आप नोडोड्स के साथ सर्वर-साइड कर सकते हैं। ..)।

यह इस बात पर निर्भर करता है कि आपके पास क्या डेटा है और आप क्या हासिल करना चाहते हैं।

आपके डेटा में कुछ प्राकृतिक "सरल" विशिष्टता है:

  • एक पूर्णांक का हैश ... पूर्णांक, जैसा कि यह अद्वितीय है, भाग्यशाली है!
  • एक स्ट्रिंग का हैश ... यह स्ट्रिंग पर निर्भर करता है, यदि स्ट्रिंग एक अद्वितीय पहचानकर्ता का प्रतिनिधित्व करता है, तो आप इसे हैश के रूप में मान सकते हैं (इसलिए कोई हैशिंग की आवश्यकता नहीं है)।
  • जो कुछ भी अप्रत्यक्ष रूप से बहुत अधिक एक अद्वितीय पूर्णांक है वह सबसे सरल मामला है
  • यह सम्मान करेगा: हैशकोड बराबर है यदि ऑब्जेक्ट समान हैं

आपके डेटा में कुछ प्राकृतिक "समग्र" विशिष्टता है:

  • उदाहरण के लिए, किसी व्यक्ति ऑब्जेक्ट के साथ, आप Firstname, lastname, जन्मतिथि ... का उपयोग करके हैश की गणना कर सकते हैं ... देखें कि जावा यह कैसे करता है: स्ट्रिंग्स के लिए अच्छा हैश फ़ंक्शन , या कुछ अन्य आईडी जानकारी का उपयोग करें जो आपके usecase के लिए सस्ती और अद्वितीय है

आपको पता नहीं है कि आपका डेटा क्या होगा:

  • सौभाग्य ... आप स्ट्रिंग को क्रमबद्ध कर सकते हैं और यह जावा शैली हैश कर सकते हैं, लेकिन यह महंगा हो सकता है यदि स्ट्रिंग बड़ी है और यह टकराव से भी नहीं बचेगा और पूर्णांक (हैश) का हैश कहेंगे।

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

व्यवहार में आपको दो चीजों की आवश्यकता होती है: पर्याप्त विशिष्टता, पर्याप्त गति

इसके अलावा यह होना बहुत अच्छा है: "हैशकोड बराबर है यदि ऑब्जेक्ट समान हैं"


0

यदि आप वास्तव में सेट व्यवहार चाहते हैं (मैं जावा ज्ञान द्वारा जा रहा हूं), तो आपको जावास्क्रिप्ट में समाधान खोजने के लिए कठिन दबाया जाएगा। अधिकांश डेवलपर्स प्रत्येक ऑब्जेक्ट का प्रतिनिधित्व करने के लिए एक अद्वितीय कुंजी की सिफारिश करेंगे, लेकिन यह सेट के विपरीत है, इसमें आप एक अद्वितीय कुंजी के साथ प्रत्येक दो समान ऑब्जेक्ट प्राप्त कर सकते हैं। जावा एपीआई डुप्लिकेट मानों के लिए हैश कोड मानों की तुलना करके जांचने का काम करता है, न कि चाबियों का, और चूंकि जावास्क्रिप्ट में ऑब्जेक्ट्स का कोई हैश कोड वैल्यू प्रतिनिधित्व नहीं है, इसलिए ऐसा करना लगभग असंभव हो जाता है। यहां तक ​​कि प्रोटोटाइप जेएस लाइब्रेरी भी इस कमी को स्वीकार करती है, जब वह कहती है:

"हैश को एक साहचर्य सरणी के रूप में माना जा सकता है, मूल्यों की अनूठी कुंजी बांधना (जो कि अद्वितीय नहीं हैं) ..."

http://www.prototypejs.org/api/hash


0

पलकविहीनता के जवाब के अलावा, यहां एक फ़ंक्शन है जो किसी भी वस्तु के लिए एक प्रतिलिपि प्रस्तुत करने योग्य, अद्वितीय आईडी देता है:

var uniqueIdList = [];
function getConstantUniqueIdFor(element) {
    // HACK, using a list results in O(n), but how do we hash e.g. a DOM node?
    if (uniqueIdList.indexOf(element) < 0) {
        uniqueIdList.push(element);
    }
    return uniqueIdList.indexOf(element);
}

जैसा कि आप देख सकते हैं कि यह लुक-अप के लिए एक सूची का उपयोग करता है जो बहुत ही अक्षम है, हालांकि यह सबसे अच्छा है जो मैं अभी तक पा सकता हूं।


0

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

मैंने एक छोटी सी लाइब्रेरी लिखी है जो ऑब्जेक्ट्स से हैश बनाता है, जिसे आप आसानी से इस उद्देश्य के लिए उपयोग कर सकते हैं। वस्तुओं का एक अलग क्रम भी हो सकता है, हैश समान होगा। आंतरिक रूप से आप अपने हैश (djb2, md5, sha1, sha256, sha512, ripemd160) के लिए विभिन्न प्रकारों का उपयोग कर सकते हैं।

यहाँ प्रलेखन से एक छोटा सा उदाहरण है:

var hash = require('es-hash');

// Save data in an object with an object as a key
Object.prototype.toString = function () {
    return '[object Object #'+hash(this)+']';
}

var foo = {};

foo[{bar: 'foo'}] = 'foo';

/*
 * Output:
 *  foo
 *  undefined
 */
console.log(foo[{bar: 'foo'}]);
console.log(foo[{}]);

पैकेज का उपयोग या तो ब्राउज़र और नोड-जेएस में किया जा सकता है।

रिपोजिटरी: https://bitbucket.org/tehrengruber/es-js-hash


0

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

लुकिंग ऑब्जेक्ट बनाना

var lookup = {};

हैशकोड फ़ंक्शन सेट करना

function getHashCode(obj) {
    var hashCode = '';
    if (typeof obj !== 'object')
        return hashCode + obj;
    for (var prop in obj) // No hasOwnProperty needed
        hashCode += prop + getHashCode(obj[prop]); // Add key + value to the result string
    return hashCode;
}

वस्तु

var key = getHashCode({ 1: 3, 3: 7 });
// key = '1337'
lookup[key] = true;

सरणी

var key = getHashCode([1, 3, 3, 7]);
// key = '01132337'
lookup[key] = true;

अन्य प्रकार

var key = getHashCode('StackOverflow');
// key = 'StackOverflow'
lookup[key] = true;

अंतिम परिणाम

{ 1337: true, 01132337: true, StackOverflow: true }

ध्यान दें कि getHashCodeवस्तु या सरणी खाली होने पर कोई मूल्य वापस नहीं करता है

getHashCode([{},{},{}]);
// '012'
getHashCode([[],[],[]]);
// '012'

यह @ijmacd समाधान के समान है केवल निर्भरता getHashCodeनहीं है JSON


आपको इसके साथ परिपत्र संदर्भों की समस्या है
tuxSlayer

@tuxSlayer मुझे बताने के लिए धन्यवाद। आप अपनी आवश्यकताओं के साथ आसानी से इस कोड का विस्तार कर सकते हैं, लेकिन मुझे उम्मीद है कि यह विचार कुछ हद तक स्पष्ट है :)
A1rPun

यह बड़ी वस्तुओं के लिए बहुत लंबी चाबियाँ पैदा करेगा जो स्मृति और प्रदर्शन को बहुत मुश्किल से मार सकती है
गर्सहोम

0

मैंने पलक और किमखा के जवाबों को मिला दिया।

निम्नलिखित कोणीयज सेवा है और यह संख्याओं, तारों और वस्तुओं का समर्थन करता है।

exports.Hash = () => {
  let hashFunc;
  function stringHash(string, noType) {
    let hashString = string;
    if (!noType) {
      hashString = `string${string}`;
    }
    var hash = 0;
    for (var i = 0; i < hashString.length; i++) {
        var character = hashString.charCodeAt(i);
        hash = ((hash<<5)-hash)+character;
        hash = hash & hash; // Convert to 32bit integer
    }
    return hash;
  }

  function objectHash(obj, exclude) {
    if (exclude.indexOf(obj) > -1) {
      return undefined;
    }
    let hash = '';
    const keys = Object.keys(obj).sort();
    for (let index = 0; index < keys.length; index += 1) {
      const key = keys[index];
      const keyHash = hashFunc(key);
      const attrHash = hashFunc(obj[key], exclude);
      exclude.push(obj[key]);
      hash += stringHash(`object${keyHash}${attrHash}`, true);
    }
    return stringHash(hash, true);
  }

  function Hash(unkType, exclude) {
    let ex = exclude;
    if (ex === undefined) {
      ex = [];
    }
    if (!isNaN(unkType) && typeof unkType !== 'string') {
      return unkType;
    }
    switch (typeof unkType) {
      case 'object':
        return objectHash(unkType, ex);
      default:
        return stringHash(String(unkType));
    }
  }

  hashFunc = Hash;

  return Hash;
};

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

Hash('hello world'), Hash('hello world') == Hash('hello world')
Hash({hello: 'hello world'}), Hash({hello: 'hello world'}) == Hash({hello: 'hello world'})
Hash({hello: 'hello world', goodbye: 'adios amigos'}), Hash({hello: 'hello world', goodbye: 'adios amigos'}) == Hash({goodbye: 'adios amigos', hello: 'hello world'})
Hash(['hello world']), Hash(['hello world']) == Hash(['hello world'])
Hash(1), Hash(1) == Hash(1)
Hash('1'), Hash('1') == Hash('1')

उत्पादन

432700947 true
-411117486 true
1725787021 true
-1585332251 true
1 true
-1881759168 true

व्याख्या

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

पलकविहीनता वस्तु तुलना का उपयोग स्वयं संदर्भित वस्तुओं द्वारा शिशु पुनरावृत्ति को रोकने के लिए किया जाता है।

प्रयोग

मैंने इस सेवा को बनाया ताकि मैं एक त्रुटि सेवा प्राप्त कर सकूं जो वस्तुओं के साथ उपलब्ध है। ताकि एक सेवा किसी दिए गए ऑब्जेक्ट के साथ त्रुटि दर्ज कर सके और दूसरा यह निर्धारित कर सके कि क्या कोई त्रुटि पाई गई थी।

अर्थात

JsonValidation.js

ErrorSvc({id: 1, json: '{attr: "not-valid"}'}, 'Invalid Json Syntax - key not double quoted');

UserOfData.js

ErrorSvc({id: 1, json: '{attr: "not-valid"}'});

यह लौटेगा:

['Invalid Json Syntax - key not double quoted']

जबकि

ErrorSvc({id: 1, json: '{"attr": "not-valid"}'});

यह वापस आ जाएगी

[]

0

बस के साथ छिपे हुए गुप्त संपत्ति का उपयोग करें defineProperty enumerable: false

यह बहुत तेजी से काम करता है :

  • पहला रीड यूनिक आई: 1,257,500 ऑप्स / एस
  • अन्य सभी: 309,226,485 ऑप्स / एस
var nextObjectId = 1
function getNextObjectId() {
    return nextObjectId++
}

var UNIQUE_ID_PROPERTY_NAME = '458d576952bc489ab45e98ac7f296fd9'
function getObjectUniqueId(object) {
    if (object == null) {
        return null
    }

    var id = object[UNIQUE_ID_PROPERTY_NAME]

    if (id != null) {
        return id
    }

    if (Object.isFrozen(object)) {
        return null
    }

    var uniqueId = getNextObjectId()
    Object.defineProperty(object, UNIQUE_ID_PROPERTY_NAME, {
        enumerable: false,
        configurable: false,
        writable: false,
        value: uniqueId,
    })

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