अवरोही क्रम में संख्याओं को छाँटना लेकिन शुरुआत में `0` के साथ


36

मेरे पास जावास्क्रिप्ट में एक चुनौती है कि मैं कुछ समय के लिए पहले ही पता लगाने की कोशिश कर रहा हूं।

इस सरणी पर विचार करें:

let arr = [0, 1, 0, 2, 0, 3, 0, 4, 0, 5];

मुझे इस परिणाम का उत्पादन करना है:

arr = [0, 0, 0, 0, 0, 5, 4, 3, 2, 1]

मैं तर्क की इस पंक्ति का अनुसरण कर रहा हूं कि शून्य मान को सामने लाएं, सूचकांक मान को समायोजित करें:

arr.sort((x, y) => {
    if (x !== 0) {
        return 1;
    }

    if (x === 0) {
        return -1;
    }

    return y - x;
});

लेकिन मैं इस परिणाम पर अटक गया हूं:

arr = [0, 0, 0, 0, 0, 1, 2, 3, 4, 5]

किसी को भी इस पर हल करने के लिए कोई सुझाव है?


6
क्या यह गारंटी है कि कोई नकारात्मक संख्या नहीं है?
माइकल - जहां

2
अगर अंतिम लाइन पर स्विच नहीं किया जाता है तो क्या यह ठीक नहीं है return x - y;?
मूविंग डक

2
क्या शून्य को गिनना और हटाना, शेष तत्वों को सामान्य रूप से क्रमबद्ध करना जावास्क्रिप्ट में कुशल होगा? (एक कस्टम तुलनित्र के बिना उम्मीद है कि जेएस इंजन बिल्ट-इन नंबर-सॉर्टिंग फ़ंक्शन का उपयोग कर सकता है)। फिर परिणाम के लिए शून्य की सही संख्या का संकेत दें। यदि कई शून्य हैं, तो छंटाई से पहले उन्हें हटाने से एक छोटी सी समस्या हो जाती है। या एक पास के साथ सरणी की शुरुआत में शून्य स्वैप करें, फिर सरणी की पूंछ को सॉर्ट करें?
पीटर कॉर्डेस

2
क्या यह भी कभी मिलता है return y - x;? जावास्क्रिप्ट में भी, मैं ऐसा कुछ भी नहीं सोच सकता जो न तो होगा ===0और न ही होगा !==0
जॉर्ज टी

2
जवाब के लिए JSPerf: jsperf.com/stackoverflow-question-58933996-v2
सलमान ए

जवाबों:


35

आप शून्य जैसे झूठे मूल्यों के लिए bऔर a(नीचे उतरते छँटाई के लिए) और ले जा सकते हैं Number.MAX_VALUE

इस:

Number.MAX_VALUE - Number.MAX_VALUE

शून्य के बराबर है।

let array = [0, 1, 0, 2, 0, 3, 0, 4, 0, 5];

array.sort((a, b) => (b || Number.MAX_VALUE) - (a || Number.MAX_VALUE));

console.log(...array);


13
आपका तुलना समारोह वापस आ जाएगी NaNदोनों अगर aऔर bशून्य कर रहे हैं। यह अवांछित व्यवहार हो सकता है।
dan04

20
के परिणामों Array.prototype.sortकार्यान्वयन से परिभाषित करता है, तो तुलनित्र कभी रिटर्न हैं NaN, तो यह तुलनित्र एक बुरा विचार है। यह चालाक होने की कोशिश करता है, और गलत हो जाता है।
user2357112

3
क्या होगा यदि सरणी के अंदर एक तत्व इन्फिनिटी है? तुलनात्मक संख्या 0.
Marco

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

4
बिल्कुल अन-पठनीय। शांत, लेकिन अपठनीय।
सलमान ए

24

जैसा कि mdn डॉक्स कहते हैं:

यदि ए और बी दो तत्वों की तुलना की जा रही है, तो:

यदि compareFunction(a, b)इससे कम रिटर्न मिलता है 0, तो aएक इंडेक्स से कम होता है b(यानी पहले आता है)।

अगर compareFunction(a, b) रिटर्न 0 है, तो ए और बी को एक दूसरे के संबंध में अपरिवर्तित छोड़ दें, लेकिन सभी अलग-अलग तत्वों के संबंध में क्रमबद्ध हैं। नोट: ECMAscript मानक इस व्यवहार की गारंटी नहीं देता है, इस प्रकार, सभी ब्राउज़र (जैसे मोज़िला संस्करण कम से कम 2003 तक वापस डेटिंग करते हैं) इसका सम्मान नहीं करते हैं।

यदि compareFunction(a, b) 0 से अधिक रिटर्न मिलता है, तो bएक इंडेक्स की तुलना में कम (जैसे)b पहले आता है)।

compareFunction(a, b)हमेशा एक ही मान लौटाना चाहिए जब तत्वों की एक विशिष्ट जोड़ी दिया aऔरb रूप में उसके दो तर्कों के रूप में । यदि असंगत परिणाम वापस किए जाते हैं, तो क्रम क्रम अपरिभाषित है।

तो, तुलना फ़ंक्शन का निम्न रूप है:

function compare(a, b) {
  if (a is less than b by some ordering criterion) {
    return -1;
  }
  if (a is greater than b by the ordering criterion) {
    return 1;
  }
  // a must be equal to b
  return 0;
}

let arr = [0, 1, 0, 2, 0, 3, 0, 4, 0, 5];

arr.sort((x, y) => {
    if (x > 0 && y > 0) {
        return y - x;
    }
    return x - y;
});

console.log(arr);


3
+1 जो केवल एक ही समाधान प्रतीत होता है उसे देने के लिए एक तुलनात्मक फ़ंक्शन के साथ जो वास्तव में सभी इनपुट के लिए ( मानक में परिभाषित ) संगत है, जिसमें नकारात्मक संख्याएं शामिल हैं।
इल्मरी करोनें

3
@ इल्मारियारोन: दुर्भाग्य से, तुलना नकारात्मक संख्याओं के लिए सुसंगत है , लेकिन यह नकारात्मक संख्याओं के लिए गलत तुलना है । नकारात्मक इस तुलनित्र के साथ 0 से पहले सॉर्ट करते हैं, और वे आरोही क्रम में सॉर्ट करते हैं।
user2357112

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

13

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

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

आपके द्वारा किए जाने के बाद आप सही ढंग से शून्य की सही संख्या का अनुमान लगा सकते हैं।

परिणामी कोड को पढ़ना भी उतना ही आसान है। मैंने TypedArray का उपयोग किया क्योंकि यह कुशल है और संख्यात्मक छँटाई को आसान बनाता है । लेकिन आप इस तकनीक का उपयोग नियमित ऐरे के साथ कर सकते हैं, जिसके लिए मानक मुहावरों का उपयोग (a,b)=>a-bकिया जा सकता है .sort

let arr = [0, 1, 0, 2, 0, 3, 0, 4, 0, 5];

let nonzero_arr = Int32Array.from(arr.filter(n => n != 0));
let zcount = arr.length - nonzero_arr.length;
nonzero_arr.sort();      // numeric TypedArray sorts numerically, not alphabetically

// Reverse the sorted part before copying into the final array.
nonzero_arr.reverse();

 // efficient-ish TypedArray for main result
let revsorted = new Int32Array(arr.length);   // zero-filled full size
revsorted.set(nonzero_arr, zcount);           // copy after the right number of zeros

console.log(Array.from(revsorted));      // prints strangely for TypedArray, with invented "0", "1" keys

/*
   // regular Array result
let sorted = [...Array(zcount).fill(0), ...nonzero_arr]  // IDK if this is efficient
console.log(sorted);
*/

मुझे पता नहीं है कि क्या TypedArray है .sort()और फिर .reverseअवरोही क्रम में क्रमबद्ध करने के लिए एक कस्टम तुलना फ़ंक्शन का उपयोग करने से अधिक तेज़ है। या अगर हम एक इटेरेटर के साथ मक्खी पर कॉपी-और-रिवर्स कर सकते हैं।


इसके अलावा विचार करने के लिए: केवल एक ही पूरी लंबाई के टाइप का उपयोग करें

उपयोग करने के बजाय .filter, इसके ऊपर लूप करें और जाते ही ऐरो के सामने स्वैप करें। यह आपके डेटा पर एक पास लेता है।

फिर .subarray()उसी अंतर्निहित ArrayBuffer के गैर-शून्य तत्वों के एक नए टाइप किए गए दृश्य को प्राप्त करने के लिए उपयोग करें। छंटनी जो आपको एक शून्य शुरुआत और एक सॉर्ट की गई पूंछ के साथ पूर्ण सरणी छोड़ देगी, उस प्रकार के साथ जो केवल गैर-शून्य तत्वों को देख रही है।

मुझे ऐरे या टाइपएड्रे तरीकों में विभाजन फ़ंक्शन नहीं दिखाई दिया, लेकिन मैं मुश्किल से जावास्क्रिप्ट जानता हूं। अच्छी JIT के साथ, एक लूप बिल्ट-इन विधि की तुलना में बहुत खराब नहीं होना चाहिए। (विशेष रूप से जब उस पद्धति में कॉलबैक शामिल होता है .filter, और जब तक इसका उपयोग नहीं किया जाता हैrealloc हट के तहत , तो यह पता लगाना होगा कि वास्तव में फ़िल्टर करने से पहले कितनी मेमोरी आवंटित करना है)।

मैंने टाइप -ऐरे में कनवर्ट करने .filter() से पहले नियमित-एरे का उपयोग किया । यदि आपका इनपुट पहले से ही एक टाइप्डर है तो आपको यह समस्या नहीं है, और यह रणनीति और भी आकर्षक हो जाती है।


यह शायद सरल, और / या अधिक मुहावरेदार, या कम से कम अधिक कॉम्पैक्ट हो सकता है। आईडीके अगर जेएस इंजन बहुत सारे नकल या शून्य-इनिशियलाइज़ेशन को खत्म / अनुकूलित करने का प्रबंधन करता है, या यदि यह टाइप किए गए तरीके के बजाय लूप का उपयोग करने में मदद करेगा जैसे कि रिवर्स + .सेट के बजाय पीछे की ओर कॉपी करने के लिए। मैं इसे गति-परीक्षण करने के लिए नहीं मिला; अगर कोई ऐसा करना चाहता है जो मुझे दिलचस्पी होगी।
पीटर कॉर्डेस

@ सलमान के परीक्षण के अनुसार यह उत्तर लघु आवेश के लिए बकवास की तरह है (~ 1000 तत्वों में से, 10% जिनमें से 0 हैं)। संभवत: नई सरणियों के निर्माण में दर्द होता है। या शायद TypedArray और नियमित रूप से लापरवाह मिश्रण? सभी-शून्य और गैर-शून्य + सबर्रे सॉर्ट में एक टाइपएड्रे के अंदर इन-पार्टिशन बेहतर हो सकता है, जैसा कि मेरे उत्तर के दूसरे खंड में सुझाया गया है।
पीटर कॉर्ड्स

8

बस अपने तुलनात्मक फ़ंक्शन की स्थिति को इस तरह संशोधित करें -

let arr = [-1, 0, 1, 0, 2, -2, 0, 3, -3, 0, 4, -4, 0, 5, -5];
arr.sort((a, b) => {
   if(a && b) return b-a;
   if(!a && !b) return 0;
   return !a ? -1 : 1;
});

console.log(arr);


6
यह एक सुसंगत तुलनित्र नहीं है यदि कोई भी इनपुट नकारात्मक हो सकता है; अपने तुलनित्र के अनुसार, 1 से पहले 0 प्रकार -1 से पहले किस तरह के 0. से पहले किस तरह का होता है
इल्मरी करोनें

नकारात्मक इनपुट के साथ अद्यतन
हरनूर राशिद

@ सलमान, यदि दोनों शून्य हैं, तो शर्त !a भी सही है। यह लौटेगा-1
हरुनूर रशीद

मुझे नहीं लगता है कि एक बड़ा सौदा है और बी दोनों शून्य @SalmanA हैं
हरुनूर रशीद

1
सटीक होने के लिए, मैंने उत्तर संपादित किया। बस के लिए एक शर्त जोड़ी गईa=b=0
हरनूर राशिद

6

यहां कोड गोल्फ नहीं खेलना:

let arr = [0, 1, 0, 2, 0, 3, 0, 4, 0, 5, -1];
arr.sort(function(a, b) {
  if (a === 0 && b !== 0) {
    // a is zero b is nonzero, a goes first
    return -1;
  } else if (a !== 0 && b === 0) {
    // a is nonzero b is zero, b goes first
    return 1;
  } else {
    // both are zero or both are nonzero, sort descending
    return b - a;
  }
});
console.log(arr.toString());


5

यदि यह पहले से मौजूद है तो अपनी खुद की सांख्यिक छँटाई न लिखें। आप जो करना चाहते हैं वही आप शीर्षक में कहते हैं; प्रारंभ में शून्य को छोड़कर अवरोही क्रम में क्रमबद्ध संख्याएँ।

const zeroSort = arr => [...arr.filter(n => n == 0),
                         ...new Float64Array(arr.filter(n => n != 0)).sort().reverse()];

console.log(zeroSort([0, 1, 0, 2, 0, 3, 0, 4, 0, 500]));

ऐसा कोई कोड न लिखें, जिसकी आपको आवश्यकता न हो; आपको यह गलत लग सकता है।

उठाओ TypedArray संख्या आप किस प्रकार संभाल करने के लिए सरणी चाहते हैं पर आधारित है। फ्लोट64 एक अच्छा डिफ़ॉल्ट है क्योंकि यह सभी सामान्य जेएस नंबरों को संभालता है।


@ इल्मारियारोन बेहतर?
जॉलीजोकर

आपको दो बार फ़िल्टर करने की आवश्यकता नहीं है; जैसा कि मेरा उत्तर दिखाता है कि आप एक बार फ़िल्टर कर सकते हैं और एक संख्या प्राप्त करने के लिए लंबाई घटा सकते हैं Array(n).fill(0)
पीटर कोर्ड्स

@PeterCordes हालांकि इसे संभवतः अधिक सरल कहा जा सकता है, मुझे लगता है कि कोड को पढ़ने में कम आसान होने में काफी समय लगता है
जॉली जोकर

हाँ, दक्षता के लिए tmp var के लिए 1 अतिरिक्त लाइन की आवश्यकता होगी। मेरा उत्तर कई अतिरिक्त लाइनों का उपयोग करता है क्योंकि मैं C और C ++ और असेंबली भाषा के लिए उपयोग किया जाता हूं, और अधिक अलग-अलग लाइनें होने से कंपाइलर-उत्पन्न asm का पता लगाना आसान हो जाता है जब इसके लिए जिम्मेदार कथन / प्रोफाइलिंग के लिए जिम्मेदार हो। इसके अलावा मैं आम तौर पर जेएस नहीं करता, इसलिए मुझे यह सब एक दो लाइनों पर रटना करने की कोई आवश्यकता महसूस नहीं हुई। लेकिन आप कर सकते हैं let f64arr = new Float64Array(arr.filter(n => n != 0)), तब [ ...Array(arr.length - f64arr.length).fill(0),... तो यह 1 अतिरिक्त पंक्ति जोड़ता है और अंतिम पंक्ति को सरल करता है।
पीटर कोर्ड्स

4

आप इसे इस तरह से कर सकते हैं:

let arr = [0, 1, 0, 2, 0, 3, 0, 4, 0, 5];

let result = arr.sort((a,b) => {
  if(a == 0 || b == 0)
    return a-b;
  return b-a;
})
console.log(result)

या आप यह कर सकते हैं:

let arr = [0, 1, 0, 2, 0, 3, 0, 4, 0, 5];

let result = arr.sort().sort((a,b) => {
  if(a > 0 && b > 0)
    return b-a
  return 0
})

console.log(result)


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

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