كيفية عكس الصفائف في JavaScript دون استخدام .reverse ()

في مكان وخارج المكان

الصورة عن طريق Guillaume Bolduc على Unsplash

يتعلق سؤال أو تحدي مقابلة جافا سكريبت المعتادة بعكس الصفائف في مكانها وخارجها. على وجه التحديد ، خذ هذه المشكلة من Eloquent JavaScript ، الإصدار الثاني:

اكتب دالتين reversArray و reversArrayInPlace. الأول ، reversArray ، يأخذ صفيفًا كوسيطة ويوفر صفيفًا جديدًا له نفس العناصر في الترتيب العكسي. الثاني ، reversArrayInPlace ، يقوم بما تقوم به الطريقة العكسية: إنه يعدل الصفيف المعطى كوسيطة من أجل عكس عناصره. لا يجوز استخدام الطريقة العكسية القياسية.

هذا هو الركل: لا يمكنك استخدام طريقة .reverse ().

لقد تعاملت مع هذه المشكلة في الماضي ، لكن الآن بعد أن عدت إلى دراسة جافا سكريبت بعد استراحة ، استغرق الأمر مني بعض الوقت لإعادة لف رأسي حولها. لا سيما عكس مجموعة في المكان. لمساعدتي على فهم هذه المشكلة والتفكير فيها بشكل أفضل ، قررت أن أكتب هذه المقالة.

عكس صفيف خارج الموضع

للبدء ، دعونا نصنع صفيفين:

var array1 = ["نعم" ، "لا" ، "ربما" ، "دائمًا" ، "أحيانًا" ، "أبدًا" ، "إذا"] ؛
var array2 = [5،8،2،9،5،6،3،1]؛

بالنسبة لوظيفة العكسية ، إذا كنا سننتج صفيفًا جديدًا ، فسنحتاج إلى صفيف فارغ لملءه لاحقًا:

var newArray = []؛

كتابة الخطوات في الكود الزائف:

// 1) أريد أن آخذ العنصر الأخير للصفيف ، ثم أضفه إلى newArray.
// 2) للقيام بذلك ، سأحتاج إلى التكرار خلال الصفيف من النهاية إلى البداية ، لأنني أريد أن يكون العنصر الأخير هو الأول.
// 3) أريد إخراج محتويات "newArray" عند انتهاء حلقة for.

دعنا نأتي مع الحلقة الأولى. للبدء في نهاية المصفوفة ، نريد تعيين i على طول المصفوفة مطروحًا منها 1 ، لأن فهرس المصفوفة يبدأ دائمًا عند الصفر.

var i = array.length - 1

على سبيل المثال ، سوف تعطينا array1.length 7 لأن هناك سبعة عناصر فيه. ومع ذلك ، فإن فهرس كل منها هو 0 و 1 و 2 و 3 و 4 و 5 و 6. لذلك ، من أجل البدء في العنصر بفهرس 6 ، نحتاج إلى أخذ طول الصفيف وطرح 1 .

كتابة لدينا كامل للحلقة نحصل على:

لـ (var i = arr.length - 1؛ i> = 0؛ i--)

بمعنى آخر ، نحن نطرح 1 من الفهرس بكل حلقة حتى تكون أكبر من أو تساوي ، بداية المصفوفة. (استخدام arr كاسم المعلمة في الوظيفة أدناه يشبه استخدام الصفيف. لا تدع ذلك يرميك

وظيفة العكسي (arr) {
  var newArray = []؛
  لـ (var i = arr.length - 1؛ i> = 0؛ i--) {
    newArray.push (آر [أنا])؛
  }
  إرجاع newArray؛
}

يمثل arr [i] كل عنصر في الفهرس الخاص به. في الحلقة الأولى من خلال ، arr [i] هو العنصر "إذا". في كل حلقة ، نستخدم طريقة .push () لتعني حرفيًا [دفع] arr إلى نهاية newArray.

عند تمرير الصفيف 1 إلى هذه الوظيفة ، سنحصل على:

reverseArray (array1)
⊳ ["إذا" ، "أبدًا" ، "أحيانًا" ، "دائمًا" ، "ربما" ، "لا" ، "نعم"]

عكس صفيف في المكان

تصبح الأمور على الفور أكثر تعقيدًا بالنسبة لي عند محاولة عكس مجموعة في مكانها. عندما حاولت مبدئيًا التغلب على هذه المشكلة ، كنت أحاول الحصول على العنصر الأول باستخدام .shift () ، واضبط ذلك على متغير اسمه أولاً ، ثم استخدم .push () لإضافته إلى نهاية الصفيف الأصلي. لكن المشكلة التي واجهتني هي أنني كنت فقط عكس العناصر الأولى والأخيرة مرارًا وتكرارًا مع كل حلقة ، لأن .shift () يزيل فقط العناصر الموجودة في "مؤشر الصفر" و .pop () في الأخير.

كانت هناك أيضًا مشكلة من أين تبدأ ونهاية الحلقة.

قبل المضي قدمًا ، دعنا نكتب المشكلة في الكود الزائف:

// 1) أنا أعلم أنني بحاجة إلى حلقة من خلال مجموعة. ولكن قبل معرفة مكان البدء أو النهاية ، أحتاج إلى التفكير في كيفية عكس العناصر الموجودة في الصفيف بالفعل.
// 2) الطريقة الوحيدة التي يمكنني أن أفكر في القيام بذلك هي تبديل العنصر الأول بالعنصر الأخير ، ثم العنصر الثاني بالعنصر الثاني إلى الأخير ، إلخ ، حتى تصل إلى الوسط.

بالنسبة إلى حلقة for ، لدينا أستطيع أن أبدأ في بداية أو نهاية المصفوفة ، وأنتهي عندما أكون نصف طول المصفوفة.

الطريقة التي فكرت بها في البداية هي:

لـ (var i = 0 ؛ i <= (arr.length / 2) ؛ i ++)

ثم قمت بتعيين العنصر الأول على قدم المساواة مع متغير يسمى el ، ثم تعيين العنصر الأول على قدم المساواة ، وآخر يساوي الأول (el).

إليك ما يبدو عليه:

دع el = arr [i]؛
arr [i] = arr [arr.length - 1 - i]؛
arr [arr.length - 1 - i] = el؛

لذلك مع كل حلقة ، سيتم إعادة ضبط el لتساوي العنصر التالي في الصفيف.

arr [arr.length - 1 - i] هي مجرد طريقة للقول:

  1. في الحلقة الأولى ، يكون الفهرس هو طول المصفوفة ، ناقص 1 ، ناقص قيمة i ، وهي 0. باستخدام المصفوفة 1 كمثال ، سيكون: 8 - 1 - 0 = 7. arr [7] هو العنصر الأخير من array1 ، وهو "إذا".
  2. في الحلقة الثانية ، سيكون: 8 - 1 - 1 = 6. لذلك ، فإن arr [6] سيكون العنصر الثاني إلى الأخير في المصفوفة 1 ، والذي "لا يوجد أبدًا". على وعلى حتى الوصول إلى منتصف مجموعة.

محاولة ذلك بهذه الطريقة ، يبدو:

الدالة reversArrayInPlace (arr) {
  لـ (var i = 0؛ i <= (arr.length / 2)؛ i ++) {
      دع el = arr [i]؛
      arr [i] = arr [arr.length - 1 - i]؛
      arr [arr.length - 1 - i] = el؛
  }
  عودة العودة ؛
}

ولكن في اختبار هذا ، يحدث شيء غريب مع صفائف لها طول متساوي ، مثل array2:

reverseArrayInPlace (array2)
⊳ [1 ، 3 ، 6 ، 9 ، 5 ، 2 ، 8 ، 5]

يتم عكس 9 و 5 في الوسط!

في الحالات التي يكون فيها المصفوفة لدينا رقمًا فرديًا ، مثل array1 ، فإن استخدام i <= (arr.length / 2) سيعمل ، لأن array1.length هو 3.5 ، وستستمر الحلقة طالما أني أقل من أو تساوي 3.5 . ولكن إذا كان طولنا 8 ، كما هو في الصفيف 2 ، فسوف تتوقف الحلقة عند الفهرس 4 ، والذي هو بالفعل مؤشر واحد حيث نريد التوقف. لأن الفهرس يبدأ من 0 ، نريد فعلاً التوقف عند 3.

لإصلاح ذلك ، يمكننا طرح 1 من طول المصفوفة قبل تقسيمها على 2. من أجل حسن التدبير ، يمكننا رمي Math.floor في المقدمة لتقريب الكسور العشرية إلى الأسفل إلى أقرب عدد صحيح.

الدالة reversArrayInPlace (arr) {
  لـ (var i = 0؛ i <= Math.floor ((arr.length - 1) / 2)؛ i ++) {
      دع el = arr [i]؛
      arr [i] = arr [arr.length - 1 - i]؛
      arr [arr.length - 1 - i] = el؛
  }
  عودة العودة ؛
}

للمراجعة:

  • بدأنا في بداية الصفيف في حلقة لدينا.
  • انتقلنا عبر المجموعة حتى وصلنا إلى منتصف الطريق.
  • مع كل حلقة نقوم بتعيين العنصر في i - أو arr [i] - يساوي متغير يسمى el.
  • بعد ذلك نقوم بتعيين العنصر الأول مساويًا للعنصر الأخير ، والعنصر الأخير يساوي العنصر الأول.
  • مع كل حلقة لاحقة ، عندما انتقلنا إلى الداخل ، فعلنا نفس الشيء.

أنا الصاعد جافا سكريبت ، لذلك إذا كان لديك طريقة أكثر فعالية للقيام بذلك ، أحب أن أسمع منك في قسم التعليقات أدناه!

وظيفة تتيح الاتصال (نعم) {
  إذا (نعم === صحيح) {
    console.log ( "ينكدين")؛
    console.log ( "تويتر")؛
  } آخر {
    console.log ("شكرا للقراءة!") ؛
  }
}