जावास्क्रिप्ट में एक सरणी में तत्वों को घुमाएं


86

मैं सोच रहा था कि जावास्क्रिप्ट ऐरे को घुमाने का सबसे कारगर तरीका क्या था।

मैं इस समाधान के साथ आया था, जहां एक सकारात्मक nसरणी को दाईं ओर घुमाता है, और बाईं ओर एक नकारात्मक n( -length < n < length):

Array.prototype.rotateRight = function( n ) {
  this.unshift( this.splice( n, this.length ) );
}

जो तब इस तरह इस्तेमाल किया जा सकता है:

var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
months.rotate( new Date().getMonth() );

ऊपर दिए गए मेरे मूल संस्करण में एक दोष है, जैसा कि क्रिस्टोफ़ ने टिप्पणी में कहा है , एक सही संस्करण है (अतिरिक्त रिटर्न की अनुमति देता है):

Array.prototype.rotateRight = function( n ) {
  this.unshift.apply( this, this.splice( n, this.length ) );
  return this;
}

क्या संभवतः एक जावास्क्रिप्ट ढांचे के संदर्भ में अधिक कॉम्पैक्ट और / या तेज समाधान है? (प्रस्तावित संस्करणों में से कोई भी बेली या तो अधिक कॉम्पैक्ट या तेज है)

वहाँ किसी भी जावास्क्रिप्ट फ्रेमवर्क के साथ एक सरणी में निर्मित में बारी बारी से है? (फिर भी किसी ने जवाब नहीं दिया)


1
मुझे वह नहीं मिला जो आपके उदाहरण के अनुसार करना चाहिए। आप months[new Date().getMonth()]वर्तमान महीने का नाम पाने के लिए सिर्फ इसका उपयोग क्यों नहीं करते ?
गुम्बो 12

1
@ जीन: कोड टूट गया है: जिस तरह से आप इसे करते हैं, यह स्पिलिटेड तत्वों को एक सरणी के रूप में हटा देगा और व्यक्तिगत रूप से नहीं; आपको apply()अपने कार्यान्वयन कार्य को करने के लिए उपयोग करना होगा
क्रिस्टोफ

आज इस सूची को दिखाने के लिए रोटेशन महीनों में बदल जाएगा ( Decपहली स्थिति के साथ):["Dec", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov"]
जीन विंसेंट

@ क्रिसस्टोफ़, आप सही कह रहे हैं, यह जेनेरिक रोटेट फ़ंक्शन के रूप में काम नहीं करेगा। यह केवल तभी काम करता है जब सही के बाद एक स्ट्रिंग में परिवर्तित किया जाए।
जीन विंसेंट

@ जीन: आप के माध्यम से अपने संस्करण को ठीक कर सकते हैं Array.prototype.unshift.apply(this, this.splice(...))- मेरा संस्करण एक ही काम करता है, लेकिन push()इसके बजाय का उपयोग करता हैunshift()
क्रिस्टोफ

जवाबों:


60

प्रकार-सुरक्षित, सामान्य संस्करण जो सरणी को बदल देता है:

Array.prototype.rotate = (function() {
    // save references to array functions to make lookup faster
    var push = Array.prototype.push,
        splice = Array.prototype.splice;

    return function(count) {
        var len = this.length >>> 0, // convert to uint
            count = count >> 0; // convert to int

        // convert count to value in range [0, len)
        count = ((count % len) + len) % len;

        // use splice.call() instead of this.splice() to make function generic
        push.apply(this, splice.call(this, 0, count));
        return this;
    };
})();

टिप्पणियों में, जीन ने यह मुद्दा उठाया कि कोड ओवरलोडिंग का समर्थन नहीं करता है push()और splice()। मुझे नहीं लगता कि यह वास्तव में उपयोगी है (टिप्पणियों को देखें), लेकिन एक त्वरित समाधान (कुछ हद तक एक हैक, हालांकि) लाइन को बदलने के लिए होगा

push.apply(this, splice.call(this, 0, count));

इसके साथ:

(this.push || push).apply(this, (this.splice || splice).call(this, 0, count));

का उपयोग unshift()करने के बजाय push()लगभग दोगुनी गति से ओपेरा 10 में है, जबकि एफएफ में अंतर बहुत मामूली थे; कोड:

Array.prototype.rotate = (function() {
    var unshift = Array.prototype.unshift,
        splice = Array.prototype.splice;

    return function(count) {
        var len = this.length >>> 0,
            count = count >> 0;

        unshift.apply(this, splice.call(this, count % len, len));
        return this;
    };
})();

2
Array.prototypeतरीकों का अच्छा कैशिंग ! +1
जेम्स

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

यहाँ क्या बंद करने की लागत है, बस धक्का और बंटवारे को कैश करने के लिए?
जीन विंसेंट

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

1
यह बड़े सरणियों को नहीं घुमाएगा। मैंने आज जाँच की और यह लंबाई में केवल 250891 वस्तुओं की एक सरणी को संभाल सकता है। जाहिरा तौर पर आप जितने भी तर्कों को applyविधि से पारित कर सकते हैं , एक निश्चित कॉल स्टैक आकार के साथ सीमित है। ईएस 6 के संदर्भ में प्रसार ऑपरेटर भी उसी स्टैक आकार के मुद्दे से पीड़ित होगा। नीचे मैं एक ही काम करने का एक नक्शा विधि देता हूं। यह धीमा है लेकिन लाखों वस्तुओं के लिए काम करता है। आप लूप के लिए या उसके बाद एक सरल के साथ मानचित्र को लागू कर सकते हैं और यह बहुत तेज़ हो जाएगा।
रेडू

144

आप उपयोग कर सकते हैं push(), pop(), shift()और unshift()तरीके:

function arrayRotate(arr, reverse) {
  if (reverse) arr.unshift(arr.pop());
  else arr.push(arr.shift());
  return arr;
}

उपयोग:

arrayRotate(['h','e','l','l','o']);       // ['e','l','l','o','h'];
arrayRotate(['h','e','l','l','o'], true); // ['o','h','e','l','l'];

यदि आपको countतर्क की आवश्यकता है तो मेरे अन्य उत्तर देखें: https://stackoverflow.com/a/33451102 my


यह एक गिनती नहीं है, हालांकि यह उपयोग के आधार पर एक बड़ी बात नहीं है।
JustGage

@JustGage, मैं काउंट सपोर्ट stackoverflow.com/questions/1985260/… के
युकुलिएल

2
बस एक नोट: सावधान रहें कि यह विधि घुसपैठ है और यह परम के रूप में भेजे गए सरणी में हेरफेर करेगी। इसे भेजने से पहले सरणी
fugillen

यहाँ बाएं दाएँ चर stackblitz.com/edit/typescript-vtcmhp
Dživo Jelić

38

मैं शायद ऐसा कुछ करूंगा:

Array.prototype.rotate = function(n) {
    return this.slice(n, this.length).concat(this.slice(0, n));
}

    यहाँ एक उत्परिवर्ती संस्करण संपादित करें :

Array.prototype.rotate = function(n) {
    while (this.length && n < 0) n += this.length;
    this.push.apply(this, this.splice(0, n));
    return this;
}

ध्यान रखें कि यह फ़ंक्शन मूल सरणी को अपरिवर्तित रखता है
क्रिस्टोफ़

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

@ गुंबो, जबकि लूप क्यों? हमें एन पॉजिटिव बनाने की जरूरत नहीं है, ब्याह नकारात्मक मूल्यों के साथ ही काम करता है। अंत के लिए, यह सही है लेकिन बहुत ज्यादा क्रिस्टोफ़ संस्करण है जो इसे पहले ही ओवरलोडिंग केवेट के बिना मिला।
जीन विंसेंट

@ गंबो, मेरी पिछली टिप्पणी पर सुधार, नकारात्मक संख्या केवल ब्याह (n। इस। लर्निंग) संस्करण का काम करती है। अपने संस्करण के रूप में ब्याह (0, n) का उपयोग करना, एक सकारात्मक इंट की आवश्यकता है।
जीन विंसेंट

1
मैंने n = n % this.lengthनकारात्मक और / या सीमा संख्या से बाहर जाने के लिए रिटर्न स्टेटमेंट से पहले जोड़ा है ।
Iiedmrc

25

यह फ़ंक्शन दोनों तरह से काम करता है और किसी भी संख्या के साथ काम करता है (यहां तक ​​कि सरणी लंबाई से अधिक संख्या के साथ):

function arrayRotate(arr, count) {
  count -= arr.length * Math.floor(count / arr.length);
  arr.push.apply(arr, arr.splice(0, count));
  return arr;
}

उपयोग:

for(let i = -6 ; i <= 6 ; i++) {
  console.log(arrayRotate(["🧡","💚","💙","💜","🖤"], i), i);
}

परिणाम:

[ "🖤", "🧡", "💚", "💙", "💜" ]    -6
[ "🧡", "💚", "💙", "💜", "🖤" ]    -5
[ "💚", "💙", "💜", "🖤", "🧡" ]    -4
[ "💙", "💜", "🖤", "🧡", "💚" ]    -3
[ "💜", "🖤", "🧡", "💚", "💙" ]    -2
[ "🖤", "🧡", "💚", "💙", "💜" ]    -1
[ "🧡", "💚", "💙", "💜", "🖤" ]    0
[ "💚", "💙", "💜", "🖤", "🧡" ]    1
[ "💙", "💜", "🖤", "🧡", "💚" ]    2
[ "💜", "🖤", "🧡", "💚", "💙" ]    3
[ "🖤", "🧡", "💚", "💙", "💜" ]    4
[ "🧡", "💚", "💙", "💜", "🖤" ]    5
[ "💚", "💙", "💜", "🖤", "🧡" ]    6

इस फ़ंक्शन का उपयोग करके मैं एक समस्या में भाग गया क्योंकि यह मूल सरणी को बदल देता है। मुझे यहां कुछ वर्कअराउंड मिले: stackoverflow.com/questions/14491405
ognockocaten

1
@ognockocaten यह कोई समस्या नहीं है, यह है कि यह कैसे कार्य करता है। यदि आप मूल सरणी को अनछुए रखना चाहते हैं, तो उससे पहले क्लोन करें:var arr2 = arrayRotate(arr.slice(0), 5)
युकुले

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

@ हाइब्रिडबदेव उपयोगconst immutatableArrayRotate = (arr, count) => ArrayRotate(arr.clone(), count)
युकुले

8

इसलिए इनमें से कई उत्तर अधिक जटिल और पढ़ने में मुश्किल लगते हैं। मुझे नहीं लगता कि मैंने किसी को कॉनसैट के साथ ब्याह का उपयोग करते देखा ...

function rotateCalendar(){
    var cal=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],
    cal=cal.concat(cal.splice(0,new Date().getMonth()));
    console.log(cal);  // return cal;
}

कंसोल.लॉग आउटपुट (* मई में उत्पन्न):

["May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Jan", "Feb", "Mar", "Apr"]

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

मैं इन कार्यों को एक चार-खिलाड़ी कार्ड गेम कार्यक्रम के लिए एक में जोड़ता हूं जहां सरणी ['N', 'E', 'S', 'W'] है। मैंने उन्हें अलग छोड़ दिया अगर कोई भी उनकी आवश्यकताओं के लिए कॉपी / पेस्ट करना चाहता है। अपने उद्देश्यों के लिए, मैं उन कार्यों का उपयोग करता हूं जब खेल के विभिन्न चरणों (पिनोकल) के दौरान खेलने / अभिनय करने के लिए किसकी बारी है। मैंने गति के लिए परीक्षण करने की जहमत नहीं उठाई, इसलिए यदि कोई और चाहता है, तो बेझिझक मुझे परिणाम बताएं।

* ध्यान दें, फ़ंक्शन के बीच एकमात्र अंतर "+1" है।

function rotateToFirst(arr,val){  // val is Trump Declarer's seat, first to play
    arr=arr.concat(arr.splice(0,arr.indexOf(val)));
    console.log(arr); // return arr;
}
function rotateToLast(arr,val){  // val is Dealer's seat, last to bid
    arr=arr.concat(arr.splice(0,arr.indexOf(val)+1));
    console.log(arr); // return arr;
}

संयोजन समारोह ...

function rotateArray(arr,val,pos){
    // set pos to 0 if moving val to first position, or 1 for last position
    arr=arr.concat(arr.splice(0,arr.indexOf(val)+pos));
    return arr;
}
var adjustedArray=rotateArray(['N','E','S','W'],'S',1);

adjustedArray =

W,N,E,S

1
अच्छा जवाब। इससे पहले कि आप अंधेरे की ओर (PHP) पर गए थे?
निक

... मैं अंधेरे पक्ष में पैदा हुआ था।
मिकमैकुसा

:) btw मैं इसे यहाँ
निक

6

एक अपरिवर्तनीय उदाहरण के लिए ES6 के प्रसार का उपयोग ...

[...array.slice(1, array.length), array[0]]

तथा

[array[array.items.length -1], ...array.slice(0, array.length -1)]

यह शायद सबसे कुशल नहीं है, लेकिन यह संक्षिप्त है।


5

टुकड़ा और विनाशकारी के साथ आसान समाधान:

const rotate = (arr, count = 1) => {
  return [...arr.slice(count, arr.length), ...arr.slice(0, count)];
};

const arr = [1,2,3,4,5];

console.log(rotate(arr, 1));  // [2, 3, 4, 5, 1]
console.log(rotate(arr, 2));  // [3, 4, 5, 1, 2]
console.log(rotate(arr, -2)); // [4, 5, 1, 2, 3]
console.log(rotate(arr, -1)); // [5, 1, 2, 3, 4]


2
यह वास्तव में अच्छा है! आप count === 0डिफ़ॉल्ट मान सेट करके चेक करने की आवश्यकता से बच सकते हैं । यह आपको इसे एक-लाइनर बनाने की अनुमति देगा:const rotate = (arr, n = 1) => [...arr.slice(n, arr.length), ...arr.slice(0, n)];
निक एफ

@ अच्छा, धन्यवाद! इस तरह नहीं सोचा था।

4

यहाँ एक सरणी में आइटम को शिफ्ट करने का एक बहुत ही सरल तरीका है:

function rotate(array, stepsToShift) {

    for (var i = 0; i < stepsToShift; i++) {
        array.unshift(array.pop());
    }

    return array;
}

3

@Christoph, आपने एक साफ कोड किया है, लेकिन मुझे जो मिला, उससे 60% धीमा । परिणाम को jsPerf पर देखें: http://jsperf.com/js-rotate-array/2 [संपादित करें] अब ठीक है और अधिक ब्राउज़र हैं जो स्पष्ट रूप से चुड़ैल नहीं हैं

var rotateArray = function(a, inc) {
    for (var l = a.length, inc = (Math.abs(inc) >= l && (inc %= l), inc < 0 && (inc += l), inc), i, x; inc; inc = (Math.ceil(l / inc) - 1) * inc - l + (l = inc))
    for (i = l; i > inc; x = a[--i], a[i] = a[i - inc], a[i - inc] = x);
    return a;
};

var array = ['a','b','c','d','e','f','g','h','i'];

console.log(array);
console.log(rotateArray(array.slice(), -1)); // Clone array with slice() to keep original

@molokocolo वास्तव में आपका समाधान धीमी गति से चलेगा क्योंकि वेतन वृद्धि अधिक होगी क्योंकि आप लूप का उपयोग कर रहे हैं। मैंने आपके परीक्षण के मामले को 5 की वृद्धि के साथ अद्यतन किया है और यह तब धीमी गति से चलता है: jsperf.com/js-rotate-array/3
जीन विंसेंट

मुझे पता नहीं है कि क्या कर रहा है रोटेट्रे () फ़ंक्शन ^ ^ केवल यह काम करता है :) (यह एक अजीब कोड है!) क्रोम फ़ायरफ़ॉक्स के विपरीत व्यवहार करता है ...
molokoloco

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

1
कोड का विश्लेषण करने के बाद, मुझे एक कमजोरी मिली है, जिससे पता चलता है कि यह समाधान केवल छोटे सरणियों और कुछ रोटेशन की गणनाओं के लिए अधिक तेज़ है : jsperf.com/js-rotate-array/5 सभी ब्राउज़रों में सबसे तेजी से बँटवारा या अनशिफ्ट के साथ Google Chrome बना हुआ है समाधान। इसका मतलब है कि यह वास्तव में एरे विधि अनुकूलन का मामला है जो क्रोम अन्य ब्राउज़रों की तुलना में बेहतर करता है।
जीन विंसेंट

3

http://jsperf.com/js-rotate-array/8 देखें

function reverse(a, from, to) {
  --from;
  while (++from < --to) {
    var tmp = a[from];
    a[from] = a[to];
    a[to] = tmp;
  }
}

function rotate(a, from, to, k) {
  var n = to - from;
  k = (k % n + n) % n;
  if (k > 0) {
    reverse(a, from, from + k);
    reverse(a, from + k, to);
    reverse(a, from, to);
  }
}

3

जब मुझे 'आज' के साथ दिनों की सूची शुरू करने के लिए तैयार स्निपेट नहीं मिला, तो मैंने इसे इस तरह किया (काफी सामान्य नहीं, शायद उपरोक्त उदाहरणों की तुलना में कम परिष्कृत, लेकिन काम किया):

//returns 7 day names with today first
function startday() {
    const days = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
    let today = new Date();
    let start = today.getDay(); //gets day number
    if (start == 0) { //if Sunday, days are in order
        return days
    }
    else { //if not Sunday, start days with today
        return days.slice(start).concat(days.slice(0,start))
    }
}

मेरे द्वारा एक बेहतर प्रोग्रामर द्वारा थोड़ा सा रिफ्लेक्टर करने के लिए धन्यवाद, यह मेरे प्रारंभिक प्रयास की तुलना में एक पंक्ति या दो छोटा है, लेकिन दक्षता पर आगे की कोई भी टिप्पणी स्वागत योग्य है।


3
function rotate(arr, k) {
for (var i = 0; i < k+1; i++) {
    arr.push(arr.shift());
}
return arr;
}
//k work as an index array
console.log(rotate([1, 2, 7, 4, 5, 6, 7], 3)); //[5,6,7,1,2,7,4]
console.log(rotate([-1, -100, 3, 99], 2));     //[99,-1,-100,3]

3
// Example of array to rotate
let arr = ['E', 'l', 'e', 'p', 'h', 'a', 'n', 't'];

// Getting array length
let length = arr.length;

// rotation < 0 (move left), rotation > 0 (move right)
let rotation = 5;

// Slicing array in two parts
let first  = arr.slice(   (length - rotation) % length, length); //['p', 'h', 'a' ,'n', 't']
let second = arr.slice(0, (length - rotation) % length); //['E', 'l', 'e']

// Rotated element
let rotated = [...first, ...second]; // ['p', 'h', 'a' ,'n', 't', 'E', 'l', 'e']

कोड की एक पंक्ति में:

let rotated = [...arr.slice((length - rotation) % length, length), ...arr.slice(0, (length - rotation) % length)];

2

स्वीकृत उत्तर में कॉल स्टैक आकार से बड़े सरणियों को संभालने में सक्षम नहीं होने का दोष है जो सत्र पर निर्भर करता है लेकिन लगभग 100 ~ 300K आइटम की तरह होना चाहिए। उदाहरण के लिए, वर्तमान क्रोम सत्र में मैंने कोशिश की थी कि यह 250891 था। कई मामलों में आप यह भी नहीं जानते होंगे कि सरणी किस आकार में गतिशील रूप से विकसित हो सकती है। तो यह एक गंभीर समस्या है।

इस सीमा को पार करने के लिए, मुझे लगता है कि एक दिलचस्प विधि Array.prototype.map()एक गोलाकार तरीके से सूचकांकों को पुनर्व्यवस्थित करके तत्वों का उपयोग और मानचित्रण कर रही है। यह विधि एक पूर्णांक तर्क लेती है। यदि यह तर्क सकारात्मक है तो यह बढ़ते हुए सूचकांकों पर और यदि घटती हुई सूचकांकों की दिशा में नकारात्मक होगा। इसमें केवल O (n) समय की जटिलता है और बिना किसी समस्या के लाखों आइटम्स को हैंडल करने के दौरान इसे कॉल किए बिना एक नई सरणी लौटाएगा। देखते हैं कि यह कैसे काम करता है;

Array.prototype.rotate = function(n) {
var len = this.length;
return !(n % len) ? this
                  : n > 0 ? this.map((e,i,a) => a[(i + n) % len])
                          : this.map((e,i,a) => a[(len - (len - i - n) % len) % len]);
};
var a = [1,2,3,4,5,6,7,8,9],
    b = a.rotate(2);
console.log(JSON.stringify(b));
    b = a.rotate(-1);
console.log(JSON.stringify(b));

वास्तव में बाद में मुझे दो मामलों पर आलोचना की गई है;

  1. सकारात्मक या नकारात्मक इनपुट के लिए सशर्त की कोई आवश्यकता नहीं है क्योंकि यह DRY के उल्लंघन का खुलासा करता है। आप इसे एक मानचित्र के साथ कर सकते हैं क्योंकि प्रत्येक नकारात्मक n में एक सकारात्मक समतुल्य है (पूरी तरह से सही ..)
  2. एक सरणी फ़ंक्शन को वर्तमान सरणी को बदलना चाहिए या एक नई सरणी बनाना चाहिए, आपका फ़ंक्शन या तो इस बात पर निर्भर कर सकता है कि क्या शिफ्ट आवश्यक है या नहीं (पूरी तरह से सही है)

मैंने निम्नानुसार कोड को संशोधित करने का निर्णय लिया है;

Array.prototype.rotate = function(n) {
var len = this.length;
return !(n % len) ? this.slice()
                  : this.map((e,i,a) => a[(i + (len + n % len)) % len]);
};
var a = [1,2,3,4,5,6,7,8,9],
    b = a.rotate(10);
console.log(JSON.stringify(b));
    b = a.rotate(-10);
console.log(JSON.stringify(b));

तो फिर; निश्चित रूप से जेएस फंक्शनलर्स जैसे Array.prototype.map()उनके समकक्षों की तुलना में धीमे हैं , जो कि सादे जेएस में कोडित हैं। 100% से अधिक प्रदर्शन हासिल करने के लिए, निम्नलिखित में से शायद मेरी पसंद Array.prototype.rotate()होगी यदि मुझे कभी उत्पादन कोड में एक सरणी को घुमाने की जरूरत हो, जैसे कि मैं अपने प्रयास में उपयोग करता हूंString.prototype.diff()

Array.prototype.rotate = function(n){
  var len = this.length,
      res = new Array(this.length);
  if (n % len === 0) return this.slice();
  else for (var i = 0; i < len; i++) res[i] = this[(i + (len + n % len)) % len];
  return res;
};

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

@ जीन विंसेंट हाँ आप सही हैं .. वास्तव में नक्शा धीमा हो सकता है फिर भी मेरा मानना ​​है कि आदर्श घूर्णन तर्क यह है। मैंने सिर्फ तार्किक दृष्टिकोण दिखाने की कोशिश की। मानचित्र को आसानी से लूप के साथ सरल बनाया जा सकता है और इससे गति में महत्वपूर्ण सुधार होगा ... हालांकि असली बात यह है कि स्वीकृत जवाब में कुछ अन्य भाषाओं को ध्यान में रखते हुए विकसित किया गया है। यह JS के लिए आदर्श नहीं है .... जब सरणी आकार कॉल स्टैक आकार से बड़ा होता है तो भी नहीं चलेगा। (मेरे मामले में और इस सत्र में यह केवल २५० items ९ १ आइटमों के साथ सीमित हो गया) तो ऐसा ही है ..!
रेडू

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

2

यह फ़ंक्शन छोटे सरणियों के लिए स्वीकृत उत्तर की तुलना में थोड़ा तेज़ है, लेकिन बड़े सरणियों के लिए बहुत तेज़ है। यह फ़ंक्शन सरणी की लंबाई से अधिक घूर्णन की एक मनमानी संख्या के लिए भी अनुमति देता है, जो मूल फ़ंक्शन की एक सीमा है।

अन्त में, स्वीकृत उत्तर विपरीत दिशा में वर्णित अनुसार घूमता है।

const rotateForEach = (a, n) => {
    const l = a.length;
    a.slice(0, -n % l).forEach(item => a.push( item ));
    return a.splice(n % l > 0 ? (-n % l) : l + (-n % l));
}

और कार्यात्मक समतुल्य (जो लगता है कि कुछ प्रदर्शन लाभ भी है):

const rotateReduce = (arr, n) => {
    const l = arr.length;
    return arr.slice(0, -n % l).reduce((a,b) => {
        a.push( b );
        return a;
    }, arr).splice(n % l> 0 ? l + (-n % l) : -n % l);
};

आप यहां प्रदर्शन के टूटने की जांच कर सकते हैं।


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

2

संपादित करें :: अरे तो पता चलता है कि बहुत अधिक पुनरावृत्ति हो रही है। न लूप, न ब्रांचिंग।

फिर भी किसी भी आकार के एन के लिए दाएं रोटेशन के लिए नकारात्मक एन और बाएं एन के लिए पॉजिटिव एन के साथ काम करता है, म्यूटेशन फ्री

function rotate(A,n,l=A.length) {
  const offset = (((n % l) + l) %l)
  return A.slice(offset).concat(A.slice(0,offset))
}

यहाँ गिगल्स के लिए कोड गोल्फ संस्करण है

const r = (A,n,l=A.length,i=((n%l)+l)%l)=>A.slice(i).concat(A.slice(0,i))

EDIT1 :: * शाखा रहित, उत्परिवर्तन रहित कार्यान्वयन।

तो हे, पता चला कि मेरे पास एक शाखा थी जहां मुझे इसकी आवश्यकता नहीं थी। यहाँ एक काम कर समाधान है। ऋणात्मक संख्या = सही घुमाएँ | संख्या | पॉजिटिव संख्या = बाएं घुमाकर संख्या

function r(A,n,l=A.length) {
  return A.map((x,i,a) => A[(((n+i)%l) + l) % l])
}

समीकरण ((n%l) + l) % ln के किसी भी मनमाने ढंग से बड़े मूल्यों के बिल्कुल सकारात्मक और नकारात्मक संख्याओं को दर्शाता है

मूल

दाएं और बाएं घुमाएं। सकारात्मक के साथ बाईं ओर घुमाएं n, नकारात्मक के साथ दाएं घुमाएं n

के बड़े अश्लील इनपुट के लिए काम करता है n

कोई म्यूटेशन मोड नहीं। इन उत्तरों में बहुत अधिक उत्परिवर्तन।

इसके अलावा, अधिकांश उत्तरों की तुलना में कम संचालन। कोई पॉप नहीं, कोई धक्का नहीं, कोई ब्याह नहीं, कोई बदलाव नहीं।

const rotate = (A, num ) => {
   return A.map((x,i,a) => {
      const n = num + i
      return n < 0 
        ? A[(((n % A.length) + A.length) % A.length)]
        : n < A.length 
        ? A[n] 
        : A[n % A.length]
   })
}

या

 const rotate = (A, num) => A.map((x,i,a, n = num + i) => 
  n < 0
    ? A[(((n % A.length) + A.length) % A.length)]
    : n < A.length 
    ? A[n] 
    : A[n % A.length])

//test
rotate([...Array(5000).keys()],4101)   //left rotation
rotate([...Array(5000).keys()],-4101000)  //right rotation, num is negative

// will print the first index of the array having been rotated by -i
// demonstrating that the rotation works as intended
[...Array(5000).keys()].forEach((x,i,a) => {
   console.log(rotate(a,-i)[0])
}) 
// prints even numbers twice by rotating the array by i * 2 and getting the first value
//demonstrates the propper mapping of positive number rotation when out of range
[...Array(5000).keys()].forEach((x,i,a) => {
   console.log(rotate(a,i*2)[0])
})

स्पष्टीकरण:

अनुक्रमणिका ऑफसेट पर A के प्रत्येक अनुक्रमणिका के मान को मैप करें। इस मामले में

offset = num

अगर offset < 0तब offset + index + positive length of Aउलटा ऑफसेट को इंगित करेगा।

यदि offset > 0 and offset < length of Aतब बस वर्तमान सूचकांक को A के ऑफसेट इंडेक्स में मैप करें।

अन्यथा, सरणी की सीमा में ऑफसेट मैप करने के लिए ऑफसेट और लंबाई modulo।

उदाहरण के लिए ले लो offset = 4और offset = -4

जब offset = -4, और A = [1,2,3,4,5], प्रत्येक सूचकांक के लिए, offset + indexपरिमाण (या Math.abs(offset)) छोटा कर देगा।

आइए पहले नकारात्मक n के सूचकांक के लिए गणना की व्याख्या करें। A[(((n % A.length) + A.length) % A.length)+0]और धमकाया गया। मत बनो। इसे काम करने में मुझे 3 मिनट लगे।

  1. हम जानते हैं nकि नकारात्मक है क्योंकि मामला है n < 0। यदि संख्या ऐरे की सीमा से बड़ी है, तो इसे रेंज में n % A.lengthमैप करेगा।
  2. n + A.lengthA.lengthसही मात्रा में ऑफसेट करने के लिए उस संख्या को जोड़ें ।
  3. हम जानते हैं nकि नकारात्मक है क्योंकि मामला है n < 0। सही मात्रा में ऑफसेट n + A.lengthकरने के A.lengthलिए उस संख्या को जोड़ें ।
  4. अगला इसे मोडुलो का उपयोग करके ए की लंबाई की सीमा तक मैप करें। गणना के परिणाम को एक अनुक्रमिक सीमा में मैप करने के लिए दूसरा मोडुलस आवश्यक है

    यहां छवि विवरण दर्ज करें

  5. पहला सूचकांक: -4 + 0 = -4। A.length = 5. A.length - 4 = 1. A 2 है 2. मैप इंडेक्स 0 से 2।[2,... ]

  6. अगला सूचकांक, -4 + 1 = -3। 5 + -3 = 2. ए 2 है 3. मैप इंडेक्स 1 से 3।[2,3... ]
  7. आदि।

उसी प्रक्रिया पर लागू होता है offset = 4। जब offset = -4, और A = [1,2,3,4,5], प्रत्येक सूचकांक के लिए, offset + indexपरिमाण को बड़ा बना देगा।

  1. 4 + 0 = 0। A [4] के मूल्य पर मैप A [0]।[5...]
  2. 4 + 1 = 5, 5 अनुक्रमण के दौरान सीमा से बाहर है, इसलिए शेष के मूल्य पर A 2 को मैप करें 5 / 5, जो कि A [0] पर 0. A 2 = मान है।[5,1...]
  3. दोहराएँ।

1
Follow a simpler approach of running a loop to n numbers and shifting places upto that element.

function arrayRotateOne(arr, n) {
  for (let i = 0; i < n; i++) {
    arr.unshift(arr.pop());
  }
  return arr;
}
console.log( arrayRotateOne([1,2,3,4,5,6],2));



function arrayRotateOne(arr,n) {
  for(let i=0; i<n;i++){
      arr.push(arr.shift());
      console.log('execute',arr)
    }
     return arr;
 }

कंसोल.लॉग (arrayRotateOne ([1,2,3,4,5,6], 2));


1

गैर उत्परिवर्तन समाधान

var arr = ['a','b','c','d']
arr.slice(1,arr.length).concat(arr.slice(0,1)

उत्परिवर्तन के साथ

var arr = ['a','b','c','d']
arr = arr.concat(arr.splice(0,1))

1

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

function rotate(arr, moveCount, displayCount) {
  const size = arr.length;

  // making sure startIndex is between `-size` and `size`
  let startIndex = moveCount % size;
  if (startIndex < 0) startIndex += size; 

  return [...arr, ...arr].slice(startIndex, startIndex + displayCount);
}

// move 3 to the right and display 4 items
// rotate([1,2,3,4,5], 3, 4) -> [4,5,1,2]

// move 3 to the left and display 4 items
// rotate([1,2,3,4,5], -3, 4) -> [3,4,5,1]

// move 11 to the right and display 4
// rotate([1,2,3,4,5], 3, 4) -> [2,3,4,5]

0

कैसे एक काउंटर को बढ़ाने के बारे में और फिर एक विभाजन के शेष भाग को सरणी लंबाई से प्राप्त करने के लिए जहां आपको माना जाता है।

var i = 0;
while (true);
{
    var position = i % months.length;
    alert(months[position]);
    ++i;
}

भाषा सिंटैक्स एक तरफ यह ठीक काम करना चाहिए।


2
यह किसी भी तरह से ऐरे को घुमाता नहीं है।
जीन विंसेंट

1
सच (जैसा कि उत्तर में कहा गया है), लेकिन यह सरणी को घुमाने के लिए बचाता है।
13

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

0

यदि आपकी सरणी बड़ी होने जा रही है और / या आप बहुत चक्कर लगाने जा रहे हैं, तो आप किसी सरणी के बजाय लिंक की गई सूची का उपयोग करने पर विचार कर सकते हैं।


सहमत, लेकिन सवाल Arrays से संबंधित है, और अधिक विशेष रूप से ऐरे क्रिया का विस्तार करने के लिए।
जीन विंसेंट

0

@molokoloco मुझे एक ऐसे फ़ंक्शन की आवश्यकता थी जिसे मैं एक दिशा में घूमने के लिए कॉन्फ़िगर कर सकता हूं - आगे के लिए सच और पिछड़े के लिए झूठ। मैंने एक स्निपेट बनाया जो एक दिशा, एक काउंटर और एक सरणी बनाता है और एक ऑब्जेक्ट को उचित दिशा में और साथ ही पूर्व, वर्तमान और अगले मूल्यों में संवर्धित काउंटर के साथ आउटपुट करता है। यह मूल सरणी को संशोधित नहीं करता है।

मैंने इसे आपके स्निपेट के खिलाफ भी देखा था और हालांकि यह तेज़ नहीं है, यह उन लोगों की तुलना में तेज़ है, जिनसे आप अपनी तुलना करते हैं - 21% धीमी http://jsperf.com/js-rotate-array/7

function directionalRotate(direction, counter, arr) {
  counter = direction ? (counter < arr.length - 1 ? counter + 1 : 0) : (counter > 0 ? counter - 1 : arr.length - 1)
  var currentItem = arr[counter]
  var priorItem = arr[counter - 1] ? arr[counter - 1] : arr[arr.length - 1]
  var nextItem = arr[counter + 1] ? arr[counter + 1] : arr[0]
  return {
    "counter": counter,
    "current": currentItem,
    "prior": priorItem,
    "next": nextItem
  }
}
var direction = true // forward
var counter = 0
var arr = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'];

directionalRotate(direction, counter, arr)

यह ऐरे को घुमाता नहीं है। इस सवाल का जवाब देने के लिए, आपको एक एरियर वापस करने की आवश्यकता है जहां पहला आइटम काउंटर पर है।
जीन विंसेंट

0

मैं देर से आ रहा हूं लेकिन मेरे पास इन अच्छे उत्तरों को जोड़ने के लिए एक ईंट है। मुझे इस तरह के समारोह को कोड करने के लिए कहा गया था और मैंने पहली बार किया था:

Array.prototype.rotate = function(n)
{
    for (var i = 0; i < n; i++)
    {
        this.push(this.shift());
    }
    return this;
}

लेकिन यह nबड़ा होने के बाद से कम कुशल प्रतीत होता है:

Array.prototype.rotate = function(n)
{
    var l = this.length;// Caching array length before map loop.

    return this.map(function(num, index) {
        return this[(index + n) % l]
    });
}

0

मुझे यकीन नहीं है कि यह सबसे कुशल तरीका है, लेकिन मुझे पसंद है जिस तरह से यह पढ़ता है, यह सबसे बड़े कार्यों के लिए काफी तेज है क्योंकि मैंने इसे उत्पादन पर परीक्षण किया है ...

function shiftRight(array) {
  return array.map((_element, index) => {
    if (index === 0) {
      return array[array.length - 1]
    } else return array[index - 1]
  })
}

function test() {
  var input = [{
    name: ''
  }, 10, 'left-side'];
  var expected = ['left-side', {
    name: ''
  }, 10]
  var actual = shiftRight(input)

  console.log(expected)
  console.log(actual)

}

test()


0

देशी, तेज, छोटे, शब्दार्थ, पुराने इंजन और "करी" पर काम करता है।

function rotateArray(offset, array) {
    offset = -(offset % array.length) | 0 // ensure int
    return array.slice(offset).concat(
        array.slice(0, offset)
    )
}

0

** जेएस के नवीनतम संस्करण का उपयोग करके हम इसे आसानी से बना सकते हैं **

 Array.prototype.rotateLeft = function (n) {
   this.unshift(...this.splice(-(n), n));
    return this
  }

यहाँ चलता है: रोटेशन की संख्या , एक सरणी जिसे आप यादृच्छिक संख्या पास कर सकते हैं

let a = [1, 2, 3, 4, 5, 6, 7];
let moves = 4;
let output = a.rotateLeft(moves);
console.log("Result:", output)

0

Arrayजेएस में नीचे निर्मित विधि है जो एक सरणी को आसानी से घुमाने के लिए इस्तेमाल किया जा सकता है और जाहिर है कि ये विधियां प्रकृति में अपरिवर्तनीय हैं।

  • push: सरणी के अंत में आइटम सम्मिलित करता है।
  • pop: सरणी के अंत से आइटम को निकालता है।
  • unshift: सरणी के आरंभ में आइटम सम्मिलित करता है।
  • shift: सरणी की शुरुआत से आइटम को निकालता है।

नीचे दिए गए समाधान ( ES6) में दो तर्क होते हैं, सरणी को घुमाया जाना चाहिए और n, सरणी को जितनी बार घुमाया जाना चाहिए, उतनी बार।

const rotateArray = (arr, n) => {
  while(arr.length && n--) {
    arr.unshift(arr.pop());
  }
  return arr;
}

rotateArray(['stack', 'overflow', 'is', 'Awesome'], 2) 
// ["is", "Awesome", "stack", "overflow"]

इसे Array.prototype में जोड़ा जा सकता है और आपके सभी एप्लिकेशन में उपयोग किया जा सकता है

Array.prototype.rotate = function(n) {
 while(this.length && n--) {
   this.unshift(this.pop());
 }
 return this;
}
[1,2,3,4].rotate(3); //[2, 3, 4, 1]

0

लूप के लिए उपयोग करना। यहाँ कदम हैं

  1. अस्थायी चर के रूप में सरणी के पहले तत्व को स्टोर करें।
  2. फिर बाईं से दाईं ओर स्वैप करें।
  3. फिर सरणी के अंतिम तत्व के लिए अस्थायी चर असाइन करें।
  4. रोटेशन की संख्या के लिए इन चरणों को दोहराएं।

function rotateLeft(arr, rotations) {
    let len = arr.length;
    for(let i=0; i<rotations; i++){ 
        let temp = arr[0];
        for(let i=0; i< len; i++){
            arr[i]=arr[i+1];
        }
        arr[len-1]=temp;
    }
    return arr;
}

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

let rotations = 3;
let output = rotateLeft(arr, rotations);
console.log("Result Array => ", output);



-2

दक्षता के बारे में निश्चित नहीं है लेकिन मैं इसे इस गैर उत्परिवर्ती तरीके से करूंगा:

	Array.prototype.rotate = function( n ) {
  
		 return this.map( (item, index)=> this[ (this.length + index + n)%this.length ] )
	}


तो, आपके उत्तर का पहला भाग "दक्षता के बारे में निश्चित नहीं है" यह कहने जैसा है कि "मुझे नहीं पता कि यह आपके प्रश्न का उत्तर देता है"। मूल प्रश्न "किसी सरणी को घुमाने के लिए एक अच्छा तरीका नहीं है", वे विशेष रूप से कॉम्पैक्टनेस और गति (मेमोरी और समय दक्षता) के बारे में नहीं पूछते हैं। प्रश्न दक्षता के बारे में है और आपने इसके घटक का उत्तर नहीं दिया है।
रीचर्डप्रिंगल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.