किसी सरणी में मान को प्रीप्रेंड करने का सबसे कुशल तरीका है


268

यह मानकर कि मेरे पास एक ऐसा सरणी है, जिसका आकार N(जहाँ N > 0) है, क्या उस सरणी को प्रस्तुत करने का अधिक कुशल तरीका है जिसके लिए O (N + 1) चरणों की आवश्यकता नहीं होगी?

कोड में, अनिवार्य रूप से, मैं वर्तमान में क्या कर रहा हूं

function prependArray(value, oldArray) {
  var newArray = new Array(value);

  for(var i = 0; i < oldArray.length; ++i) {
    newArray.push(oldArray[i]);
  }

  return newArray;
}

के रूप में ज्यादा के रूप में मैं जुड़ा हुआ सूचियों और संकेत के रूप में यद्यपि मैं महसूस प्यार वहाँ देशी जे एस डेटा प्रकार का उपयोग कर काम करने के लिए एक अधिक प्रभावी तरीका होना चाहिए
samccone

@samccone: हाँ मेरी टिप्पणी की अवहेलना करें, मुझे लगा कि आपने जावा कहा: P
GWW

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

1
क्या इसे क्लोन करने की आवश्यकता है?
रयान फ्लोरेंस

1
यदि इसे क्लोन करने की आवश्यकता है, तो unshift अनुचित है, क्योंकि यह मूल सरणी को म्यूट करेगा और प्रतिलिपि नहीं बनाएगा।
मागुका

जवाबों:


492

मैं बड़े-ओ के संदर्भ में अधिक कुशल नहीं हूं, लेकिन निश्चित रूप से unshiftविधि का उपयोग करना अधिक संक्षिप्त है:

var a = [1, 2, 3, 4];
a.unshift(0);
a; // => [0, 1, 2, 3, 4]

[संपादित करें]

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

a.slice().unshift(0); // Use "slice" to avoid mutating "a".

[संपादित करें 2]

पूर्णता के लिए prependArray(...), Array unshift(...)विधि का लाभ लेने के लिए OP के उदाहरण के बजाय निम्नलिखित फ़ंक्शन का उपयोग किया जा सकता है :

function prepend(value, array) {
  var newArray = array.slice();
  newArray.unshift(value);
  return newArray;
}

var x = [1, 2, 3];
var y = prepend(0, x);
y; // => [0, 1, 2, 3];
x; // => [1, 2, 3];

190
prepend" unshift" बुलाने का निर्णय किसने लिया ?
स्कॉट स्टैफ़ोर्ड

12
unshiftइस तरह के एक सरणी ऑपरेशन के लिए @ScottStafford अधिक उपयुक्त लगता है (यह तत्वों को स्थानांतरित करता है ... अधिक या कम शारीरिक रूप से)। prependलिंक की गई सूचियों के लिए अधिक उपयुक्त होगा, जहाँ आप सचमुच तत्वों को प्रस्तुत करते हैं।
कैमिलबी

12
unshift शिफ्ट करने का पूरक कार्य है। इसे "प्रीपेन्ड" कहना विषम विकल्प होगा। अनशिफ्ट को पॉप के रूप में शिफ्ट करना है।
सर रॉबर्ट

9
इस समाधान के साथ केवल एक मुद्दा। Unshift () अपनी वापस नहीं करता है लंबाई , और नहीं सरणी इस उत्तर के रूप में? w3schools.com/jsref/jsref_unshift.asp
iDVB

4
pushऔर unshiftदोनों होते हैं u, जबकि popऔर shiftनहीं है।
कियान चेन

70

ईएस 6 के साथ, अब आप मूल ऑपरेटर से पहले अपने नए तत्वों के साथ एक नया सरणी बनाने के लिए प्रसार ऑपरेटर का उपयोग कर सकते हैं ।

// Prepend a single item.
const a = [1, 2, 3];
console.log([0, ...a]);

// Prepend an array.
const a = [2, 3];
const b = [0, 1];
console.log([...b, ...a]);

अपडेट 2018-08-17: प्रदर्शन

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


4
इसे 2017 तक वोट दिया जाना चाहिए। यह संक्षिप्त है। प्रसार का उपयोग करके, यह नई धारा को वापस देता है, जो आगे के संशोधनों पर श्रृंखला के लिए उपयोगी हो सकता है। यह भी शुद्ध है (इसका अर्थ है कि ए और बी अप्रभावित हैं)
सिमोन

आपने समय की तुलना में समय का उल्लेख नहीं कियाunshift
शशांक विवेक

धन्यवाद @ शशांक विवेक मैंने इसका उत्तर एक वैकल्पिक वाक्यविन्यास प्रस्तुत करने के लिए दिया था, जो मुझे लगता है कि अधिक यादगार और संक्षिप्त है। मैं अपडेट करूंगा।
फ्रैंक टैन

@FrankTan: चीयर्स :) +1
शशांक विवेक

46

यदि आप किसी सरणी को दूसरे सरणी के सामने से जोड़ रहे हैं, तो यह केवल उपयोग करने के लिए अधिक कुशल है concat। इसलिए:

var newArray = values.concat(oldArray);

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

OldArray के आकार में O (N) से बेहतर करने का कोई तरीका नहीं है, क्योंकि सरणियों को एक निश्चित स्थिति में पहले तत्व के साथ सन्निहित मेमोरी में संग्रहीत किया जाता है। यदि आप पहले तत्व से पहले सम्मिलित करना चाहते हैं, तो आपको अन्य सभी तत्वों को स्थानांतरित करने की आवश्यकता है। यदि आपको इसके आसपास कोई रास्ता चाहिए, तो @GWW ने क्या कहा और लिंक की गई सूची, या एक अलग डेटा संरचना का उपयोग करें।


2
अरे हाँ, मैं भूल गया unshift। लेकिन ध्यान दें कि a) जो कि पुराने एरे को म्यूट concatकरता है ( जबकि जो आपके लिए बेहतर है वह स्थिति पर निर्भर करता है), और b) यह केवल एक तत्व को सम्मिलित करता है।
मागुका

1
वाह, यह बहुत धीमी है। ठीक है, जैसा कि मैंने कहा, यह सरणी की एक प्रति बना रहा है (और एक नया सरणी भी बना रहा है [0]), जबकि अनशिफ्ट इसे निष्क्रिय कर रहा है। लेकिन दोनों को ओ (एन) होना चाहिए। इसके अलावा उस साइट के लिंक के लिए चीयर्स - बहुत आसान लग रहा है।
मागुका

2
ऑनलाइनर के लिए अच्छा है, क्योंकि कॉन्कैट एरे लौटाता है, और अनशिफ्ट नई लंबाई लौटाता है
जेड। खुल्ला

32

यदि आप सरणी को प्राथमिकता देना चाहते हैं (a2 a2 सरणी के साथ) तो आप निम्नलिखित का उपयोग कर सकते हैं:

var a1 = [1, 2];
var a2 = [3, 4];
Array.prototype.unshift.apply(a1, a2);
console.log(a1);
// => [3, 4, 1, 2]

6

f आपको पुराने एरे को संरक्षित करने की जरूरत है, पुराने को स्लाइस करें और स्लाइस की शुरुआत में नए मूल्य (ओं) को अनसूट करें।

var oldA=[4,5,6];
newA=oldA.slice(0);
newA.unshift(1,2,3)

oldA+'\n'+newA

/*  returned value:
4,5,6
1,2,3,4,5,6
*/

4

मेरे पास प्रचलित करने के विभिन्न तरीकों के कुछ नए परीक्षण हैं। छोटे सरणियों (<1000 हाथ) के लिए नेता एक धक्का विधि के साथ चक्र के लिए है। विशाल सरणियों के लिए, अनशिफ्ट विधि नेता बन जाती है।

लेकिन यह स्थिति केवल क्रोम ब्राउज़र के लिए वास्तविक है। फ़ायरफ़ॉक्स में unshift का कमाल अनुकूलन है और सभी मामलों में तेज़ है।

ईएस 6 स्प्रेड सभी ब्राउज़रों में 100+ गुना धीमा है।

https://jsbench.me/cgjfc79bgx/1


बहुत बढ़िया जवाब! लेकिन यह सुनिश्चित करने के लिए कि आप इसका हिस्सा नहीं खोते हैं, आप अपने परीक्षण मामलों को यहां (शायद कुछ सैंपल रन परिणामों के साथ) पुन: पेश कर सकते हैं, उदाहरण के लिए, jsbench चला जाता है।
रफिन

3

विशेष विधि है:

a.unshift(value);

लेकिन अगर आप सरणी के लिए कई तत्वों को तैयार करना चाहते हैं तो इस तरह की विधि का उपयोग करना तेज होगा:

var a = [1, 2, 3],
    b = [4, 5];

function prependArray(a, b) {
    var args = b;
    args.unshift(0);
    args.unshift(0);
    Array.prototype.splice.apply(a, args);
}

prependArray(a, b);
console.log(a); // -> [4, 5, 1, 2, 3]

2
नहीं ... अशिक्षित पहले तर्क के रूप में सरणी जोड़ देगा: var a = [4, 5]; a.unshift ([1,2,3]); console.log (क); // -> [[४, ५], १, २, ३]
१६:११ पर bjornd

4
तुम सही हो! आपको उपयोग करने की आवश्यकता होगीArray.prototype.unshift.apply(a,b);
david


1

कॉलिंग unshiftकेवल नए सरणी की लंबाई लौटाती है। इसलिए, शुरुआत में एक तत्व जोड़ने के लिए और एक नई सरणी वापस करने के लिए, मैंने यह किया:

let newVal = 'someValue';
let array = ['hello', 'world'];
[ newVal ].concat(array);

या बस प्रसार ऑपरेटर के साथ:

[ newVal, ...array ]

इस तरह, मूल सरणी अछूती रहती है।

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