2016-02-09 13 views
7

सारांश: JSON.stringify से हैश ऑब्जेक्ट्स का कोई तेज़ तरीका है?ऑब्जेक्ट तर्कों का कुशल ज्ञापन

विवरण: मेरे पास रूबी और जावास्क्रिप्ट लाइब्रेरी (NeatJSON) है जो जावास्क्रिप्ट मानों की सुंदर-प्रिंटिंग प्रदान करती है। मैंने हाल ही में एक समस्या तय की है जहां गहराई से घिरे हुए ऑब्जेक्ट्स ओ (एन!) प्रदर्शन (एन घोंसला स्तर होने के कारण) धारावाहिक और इंडेंटेशन राशि के आधार पर ज्ञापन का उपयोग करके ज्ञापन का उपयोग कर रहा है।

रूबी, the fix में, वास्तव में आसान था, क्योंकि आप कर सकते हैं वस्तुओं की अद्वितीय सेट की सरणियों द्वारा सूचकांक हैश:

build = ->(object,indent) do 
    memoizer[[object,indent]] ||= <all the rest of the code> 
end 

जावास्क्रिप्ट में, हालांकि, मैं सूचकांक किसी अन्य वस्तु से एक वस्तु नहीं कर सकते हैं (में एक अनोखा तरीका)। कई लेख मैं ऑनलाइन पाया के नेतृत्व के बाद, मैं fix the problem सामान्य रूप से करना चाहते हैं, कार्य करने के लिए तर्क का पूरा सेट पर JSON.stringify का उपयोग कर Memoization के लिए एक अद्वितीय कुंजी बनाने के लिए:

function memoize(f){ 
    var memo = {}; 
    var slice = Array.prototype.slice; 
    return function(){ 
    var args = slice.call(arguments); 
    var mkey = JSON.stringify(args); 
    if (!(mkey in memo)) memo[mkey] = f.apply(this,args); 
    return memo[mkey]; 
    } 
} 

function rawBuild(o,indent){ .. } 
var build = memoize(rawBuild); 

यह काम करता है, लेकिन (क) यह है मैं चाहता हूं कि थोड़ा धीमा, और (बी) यह हर वस्तु और मूल्य के निष्पादन (निष्पक्ष) क्रमबद्ध करने के लिए जंगली रूप से अक्षम (और सुरुचिपूर्ण) लगता है कि मैं समझदारी से क्रमबद्ध करने जा रहा हूं। कई मूल्यों के साथ एक बड़ी वस्तु को क्रमबद्ध करने का कार्य पूरे ऑब्जेक्ट में प्रत्येक अद्वितीय मूल्य (केवल पत्ती मानों) के लिए एक स्ट्रिंग और स्वरूपण परिणाम संग्रहीत करने जा रहा है।

क्या कोई आधुनिक जावास्क्रिप्ट चाल है जो मुझे विशिष्ट रूप से मूल्य की पहचान करने देगी? उदाहरण के लिए, किसी आंतरिक आईडी तक पहुंचने का कोई तरीका, या अन्यथा अनन्य पूर्णांक वाले जटिल ऑब्जेक्ट्स को जोड़ना जो मान के लिए पहचानकर्ता ढूंढने के लिए ओ (1) समय लेता है?

+0

बहुत [जावास्क्रिप्ट ऑब्जेक्ट आईडी] की (नहीं काफी dup) के समान (http://stackoverflow.com/q/2020670/405017)। काफी डुप्लिकेट नहीं है क्योंकि मुझे केवल ऑब्जेक्ट्स नहीं, अधिकांश प्रकार के मूल्य (स्ट्रिंग, बुलियन, संख्या, सरणी, ऑब्जेक्ट) के लिए एक अद्वितीय प्रतिनिधित्व खोजने की आवश्यकता है। – Phrogz

+0

क्या आप ऑब्जेक्ट वैल्यू या रेफरेंस द्वारा याद रखना चाहते हैं? दूसरे शब्दों में: 'var a = {b: 1}; var c = memoizedFn (ए); एबी = 2; var d = memoizedFn (ए); 'क्या दूसरी कॉल ज्ञापन मान का उपयोग करनी चाहिए? –

+0

@TamasHegedus संदर्भ से पूरी तरह से पर्याप्त है। – Phrogz

उत्तर

3

आप पहचान करके अपने वस्तुओं memoise करने के लिए देख रहे हैं, तो (सामग्री से नहीं), तो आप एक WeakMap जो वास्तव में इस उद्देश्य के लिए बनाया गया है का उपयोग करना चाहेंगे। हालांकि वे आदिम मूल्यों के लिए काम नहीं करते हैं, इसलिए आपको ऐसे तर्कों के लिए एक अलग समाधान की आवश्यकता होगी।

+0

यह बहुत उपयोगी लगता है। और हां, इस मामले में पहचान द्वारा ज्ञापन पर्याप्त है, क्योंकि मैं एक ही पेड़ में मूल्यों को ऊपर और नीचे क्रॉल कर रहा हूं। – Phrogz

+0

चूंकि मुझे आदिम मूल्यों का समर्थन करने की आवश्यकता है, इसलिए, यह एक ['Map'] जैसा दिखता है (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) अधिक उचित है 'वीकमैप' की तुलना में। – Phrogz

+0

@Phrogz: हाँ, उपयोग के मामले पर निर्भर करता है। एक 'वीकैप' में बेहतर मेमोरी दक्षता हो सकती है यदि कुछ ऑब्जेक्ट पहले से ही कचरा-संग्रहित हो सकता है जबकि आप अभी भी ज्ञात फ़ंक्शन पर (या चलाते हैं) दबाते हैं। – Bergi

1

यदि आपको ऑब्जेक्ट्स को याद रखने की आवश्यकता है तो यह आपके ऑब्जेक्ट्स को कुछ अद्वितीय आईडी असाइन करने के लिए समझ में आता है।

var gID = 0; 

function createNode() { 
    var obj = ... 
    obj.id = (++gID).toString(); 
} 

और अपने memo संग्रह में कुंजी के रूप में उन obj.id की का उपयोग करें।

यह सबसे तेज़ और कम से कम लालची समाधान होगा।

अद्यतन:

यदि आप चाहते हैं कि आईडी संपत्ति मौजूदा गुण के साथ संघर्ष नहीं है तो आप (कुछ अद्वितीय नाम के साथ) मानक ES5.1 Object.createProperty() उपयोग करने वाली प्रॉपर्टी गैर गणनीय बना सकते हैं या उपयोग करने के लिए ES6 symbols:

var gID = 0; 
var gUidSym = Symbol("uid"); 

function getUidOf(obj) { 
    return obj[gUidSym] 
     || (obj[gUidSym] = (++gID).toString()); 
} 
+0

दो समस्याएं: 1) मैं बनाई गई वस्तुओं को नियंत्रित नहीं करता हूं। यह एक JSON serializer है जहां लोग मुझे अपनी ऑब्जेक्ट पास करते हैं और मैं उन्हें संसाधित करता हूं। 2) क्योंकि मैं ऑब्जेक्ट की गुणों को क्रमबद्ध कर रहा हूं, आप जिस आईडी आईडी प्रॉपर्टी का प्रस्ताव देते हैं वह क्रमबद्धरण (और संभवतः मौजूदा संपत्ति के साथ संघर्ष) में शामिल हो जाएगा। – Phrogz

+1

"अद्यतन:" भाग की जांच करें। –

+0

गुण बनाना (चाहे स्ट्रिंग- या प्रतीक-नामित) में समस्या है कि यह सीलबंद वस्तुओं पर काम नहीं करता है। – Bergi

2

@ एक WeakMap की Bergi के सुझाव का उपयोग के बारे में मैं Map पता चला है, जो कुंजी के रूप में किसी भी मान प्रकार (न केवल वस्तुओं) का उपयोग की अनुमति देता है।क्योंकि मैं एक यौगिक की-विशिष्ट और खरोज में पारित मूल्य के संयोजन memoizing जरूरत स्ट्रिंग-मैं एक पदानुक्रमित Memoization ढांचा बनाया:

function memoizedBuild(){ 
    var memo = new Map; 
    return function(value,indent){ 
    var byIndent=memo.get(value); 
    if (!byIndent) memo.set(value,byIndent={}); 
    if (!byIndent[indent]) byIndent[indent] = rawBuild(value,indent); 
    return byIndent[indent]; 
    } 
} 

यह जब serializing memoization code I had been using से के बारे में 4 × तेजी से साबित हुई एक बड़ी 270 केबी JSON ऑब्जेक्ट।

ध्यान दें कि उपरोक्त कोड में मैं !byIndent[indent] उपयोग करने के लिए सिर्फ इसलिए मुझे पता है कि rawBuild एक falsey मूल्य (null, undefined, false, NaN, 0, "") वापस कभी नहीं होगा सक्षम हूं। सुरक्षित कोड लाइन कुछ ऐसा दिखाई देगा:

if (!(indent in byIndent)) byIndent[indent] = rawBuild(value,indent); 
संबंधित मुद्दे