Array#sort
इसकी तुलना और इसके तुलनित्र के व्यवहार को स्पष्ट करने में मदद करने के लिए , प्रोग्रामिंग पाठ्यक्रमों की शुरुआत में सिखाए गए इस भोले सम्मिलन के प्रकार पर विचार करें :
const sort = arr => {
for (let i = 1; i < arr.length; i++) {
for (let j = i; j && arr[j-1] > arr[j]; j--) {
[arr[j], arr[j-1]] = [arr[j-1], arr[j]];
}
}
};
const array = [3, 0, 4, 5, 2, 2, 2, 1, 2, 2, 0];
sort(array);
console.log("" + array);
एल्गोरिथ्म के रूप में प्रविष्टि प्रकार की पसंद को अनदेखा करना, हार्डकोडेड तुलनित्र पर ध्यान केंद्रित करें arr[j-1] > arr[j]
:। यह चर्चा के लिए प्रासंगिक दो समस्याएं हैं:
>
ऑपरेटर सरणी तत्वों लेकिन बहुत सी बातें आप क्रमबद्ध करना वस्तुओं का जवाब नहीं है इस तरह के रूप चाहते हो सकता है के जोड़े पर शुरू हो जाती है >
एक उचित तरीके से (यदि हम इस्तेमाल किया भी ऐसा ही होता होगा -
)।
- यहां तक कि अगर आप संख्याओं के साथ काम कर रहे हैं, तो अक्सर आप आरोही प्रकार की तुलना में कुछ अन्य व्यवस्था चाहते हैं जो यहां बेक किया गया है।
हम इन समस्याओं को एक comparefn
तर्क जोड़कर ठीक कर सकते हैं जिनसे आप परिचित हैं:
const sort = (arr, comparefn) => {
for (let i = 1; i < arr.length; i++) {
for (let j = i; j && comparefn(arr[j-1], arr[j]) > 0; j--) {
[arr[j], arr[j-1]] = [arr[j-1], arr[j]];
}
}
};
const array = [3, 0, 4, 5, 2, 2, 2, 1, 2, 2, 0];
sort(array, (a, b) => a - b);
console.log("" + array);
sort(array, (a, b) => b - a);
console.log("" + array);
const objArray = [{id: "c"}, {id: "a"}, {id: "d"}, {id: "b"}];
sort(objArray, (a, b) => a.id.localeCompare(b.id));
console.log(JSON.stringify(objArray, null, 2));
अब भोली प्रकार की दिनचर्या सामान्यीकृत है। आप देख सकते हैं कि यह कॉलबैक कब लागू किया गया है, चिंताओं के अपने पहले सेट का उत्तर देते हुए:
क्या सरणी प्रकार कॉलबैक फ़ंक्शन को सॉर्ट के दौरान कई बार कहा जाता है? यदि हां, तो मैं जानना चाहता हूं कि हर बार कौन से दो नंबर फंक्शन में आते हैं
नीचे दिए गए कोड को चलाने से पता चलता है कि हां, फ़ंक्शन को कई बार कहा जाता है और आप यह console.log
देखने के लिए उपयोग कर सकते हैं कि कौन से नंबर पास किए गए थे:
const sort = (arr, comparefn) => {
for (let i = 1; i < arr.length; i++) {
for (let j = i; j && comparefn(arr[j-1], arr[j]) > 0; j--) {
[arr[j], arr[j-1]] = [arr[j-1], arr[j]];
}
}
};
console.log("on our version:");
const array = [3, 0, 4, 5];
sort(array, (a, b) => console.log(a, b) || (a - b));
console.log("" + array);
console.log("on the builtin:");
console.log("" +
[3, 0, 4, 5].sort((a, b) => console.log(a, b) || (a - b))
);
तुम पूछो:
संख्या के दो सेट कैसे हैं फिर एक दूसरे के संबंध में क्रमबद्ध?
शब्दावली के साथ सटीक होने के लिए, a
और संख्याओं के सेटb
नहीं हैं - वे सरणी में ऑब्जेक्ट हैं (आपके उदाहरण में, वे संख्याएं हैं)।
सच्चाई यह है कि यह कोई फर्क नहीं पड़ता कि वे कैसे हल किए जाते हैं क्योंकि यह कार्यान्वयन-निर्भर है। अगर मैंने प्रविष्टि सॉर्ट की तुलना में एक अलग प्रकार के एल्गोरिथ्म का उपयोग किया था, तो तुलनित्र को संभवतः विभिन्न युग्मों की संख्याओं पर लागू किया जाएगा, लेकिन सॉर्ट कॉल के अंत में, जेएस प्रोग्रामर के लिए अपरिवर्तनीय यह है कि परिणाम सरणी के अनुसार क्रमबद्ध है तुलनित्र, तुलनित्र मान मान है कि अनुबंध का पालन करने के लिए कहा जाता है (<0 कब a < b
, 0 जब a === b
और जब 0 0a > b
)।
इस अर्थ में कि मुझे अपनी तरह के कार्यान्वयन को बदलने की स्वतंत्रता है जब तक कि मैं अपने विनिर्देश को भंग नहीं करता हूं, ईसीएमएस्क्रिप्ट के कार्यान्वयन भाषा विनिर्देश की सीमाओं के भीतर क्रमबद्ध कार्यान्वयन का चयन करने के लिए स्वतंत्र हैं , इसलिए Array#sort
संभवतः विभिन्न तुलनित्र कॉल का उत्पादन करेंगे। विभिन्न इंजनों पर। कोई ऐसा कोड नहीं लिखेगा जहां तर्क तुलना के कुछ विशेष अनुक्रम पर निर्भर करता है (न ही तुलनाकर्ता को पहले स्थान पर साइड इफेक्ट का उत्पादन करना चाहिए)।
उदाहरण के लिए, V8 इंजन (लेखन के समय) Timsort को तब आमंत्रित करता है जब सरणी कुछ पूर्व- संदूषित तत्वों की संख्या से बड़ी होती है और छोटे सरणी चंक्स के लिए द्विआधारी सम्मिलन प्रकार का उपयोग करती है । हालांकि, यह क्विकॉर्ट का उपयोग करता था जो अस्थिर है और संभवतः तुलनित्र को तर्क और कॉल का एक अलग क्रम देगा।
चूंकि विभिन्न प्रकार के कार्यान्वयन तुलनित्र फ़ंक्शन के रिटर्न मान का अलग-अलग तरीके से उपयोग करते हैं, इसलिए यह आश्चर्यजनक व्यवहार का कारण बन सकता है जब तुलनित्र अनुबंध का पालन नहीं करता है। एक उदाहरण के लिए इस धागे को देखें ।