المصفوفات (Arrays)

ما هي المصفوفات؟

المصفوفات هي نوع مهم من أنواع البيانات (data types) وتعتبر من أهم وأشهر هياكل البيانات (data structures)

وهي أشهر هياكل البيانات وأكثرها استخداما، وأبسط الطرق لتجميع البيانات، وتقريبا كل لغات البرمجة تحتوي على المصفوفات، ربما يتغير اسمها في لغة كلغة Python إلى "List" لكن اﻹسم اﻷشهر لها المصفوفات Arrays

فهي تستخدم في تخزين بيانات متعددة، على سبيل المثال لدينا عدد من المستخدمين في البرنامج، نريد أن ننشئ متغير نضع فيه أسماء كل مستخدمي البرنامج، يمكننا هنا استخدام المصفوفات arrays لتحتوي المصفوفة على أسماء كل مستخدمي البرنامج.

أهمية المصفوفات

فكر معي في هذه المشكلات وتخيل كم سيكون صعباً التعامل معها وحلها بما تعلمت حتى اﻵن بدون المصفوفات.

مشكلة عدد مستخدمي البرنامج

تخيل أنك تريد الوصول لعدد مستخدمي البرنامج، كيف تصل له؟ ببساطة يمكنك وضع كل مستخدمي البرنامج في مصفوفة، واستخدام خاصية من خصائص المصفوفة لمعرفة عدد العناصر الموجودة في المصفوفة، بالتالي يكون عدد العناصر هو عدد مستخدمي البرنامج!

سندرس خاصية طول المصفوفة في هذا الدرس

مشكلة الدول المتعددة

لنفرض أن لديك عدد من الدول مسموح بها فقط في البرنامج الخاص بك، فإن كانت دولة المستخدم ليست في هذه الدول ستمنعه من البرنامج، كيف يمكن حل المشكلة؟ لقد تعلمنا سابقاً باستخدام الشروط يمكننا التحقق مثلاً من أن المتغير يساوي كذا أم ﻻ:

var country = ""; // put country here
var allowed = "Syria";
if (country == allowed){
  console.log("أهلا بك في البرنامج");
}else{
  console.log("البرنامج غير متوفر في دولتك");
}

في المثال السابق سيسمح البرنامج فقط بدولة سوريا، أما إن كان المتغير country يساوي أي دولة غير سوريا سيتم طباعة "البرنامج غير متوفر في دولتك".

لكن ليس هذا ما نريده، نريد أن نسمح بأكثر من دولة، مثلاً سوريا وفلسطين ومصر ..! نريد أن نتحقق هل دولة المستخدم من هذه الدول المسموح بها أم ﻻ، وإن كان ﻻ نريد أن نقوم بطباعة الدول المسموح بها! لذلك لا بد من نوع جديد من البيانات يسهل علينا هذه اﻷمور ويسمح لنا بتخزين الدول المسموح بها في متغير واحد، ويعطينا إمكانية مثلاً طباعة كل الدول الموجودة في المتغير، واستخدام الحلقات التكرارية للمرور داخل هذه الدول وطباعة كل دولة .. الخ

المصفوفات برمجياً

يمكن استخدام المصفوفات لتجميع البيانات وتتعامل كأي نوع بيانات، فيمكن إرفاقها لمتغير، ويمكن طباعتها .. لكن التعبيرات الخاصة بالمصفوفات تختلف جداً عن أي نوع أخر من البيانات، فلا يمكن جمعها بعلامة "+" كاﻷعداد مثلاً ..

طريقة كتابة المصفوفات

توضع عناصر المصفوفة داخل اﻷقواس [] ويمكن أن تكون البيانات أي نوع من البيانات، يمكن أن تكون نصوصا، أعدادا، عناصر منطقية .. الخ، وتفصل بين كل عنصر واﻷخرى بـ , [1, 2, 3, 4]

أمثلة على المصفوفات

var emptyArray = []; // مصفوفة فارغة
var emptyArray = [1, 10, 20, 30, 40, 40, 20, 30]; // مصفوفة من اﻷعداد
var emptyArray = ["javascript", "nodejs", "vscode"]; // مصفوفة من النصوص
var emptyArray = [100, "dalilmobarmg", true]; // مصفوفة متنوعة

هناك لغات برمجة لا تدعم المصفوفة المتنوعة، فيجب أن تكون كل عناصر المصفوفة من نفس النوع، لكن في جافاسكريبت وبعض اللغات (PHP, Python...) يمكن أن تختلف أنواع عناصر المصفوفة


وكما ناقشنا في المشكلة السابقة نريد أن نضع أسماء عدة دول في متغير واحد، كيف؟

var countries = ["Palestine", "Syria", "Egypt"];

أساسيات المصفوفات

يمكنك الوصول لأي عنصر من عناصر المصفوفة واستخدامه، وتعديل العناصر وإضافة عنصر جديد ... والمزيد من العمليات الأخرى

الوصول لعناصر المصفوفة

كيف نصل للعناصر الموجودة في المصفوفة؟ كيف مثلاً نقوم بطباعة عنصر من عناصر المصفوفة، أو مثلاً وضعه كقيمة لمتغير، أو استخدامه في أي شيء! من أهم صفات المصفوفات أن لكل عنصر فيها مفتاح خاص به، هو عبارة عن ترتيبه في المصفوفة، ويسمى باﻹنجليزية (index) ولأن الحاسوب كما نعرف يبدأ العد من صفر وليس واحد فإن العنصر اﻷول في المصفوفة السابقة "Palestine" مفتاحه 0 وكذلك العنصر الثاني "Syria" مفتاحه 1 وهكذا...

وإذا كان إسم المصفوفة countries فإن العنصر اﻷول فيها يمكنك الوصول له عن طريق مفتاحه كالتالي: countries[0]

جرب اﻷمثلة التالية:

var countries = ["Palestine", "Syria", "Egypt"];
console.log(countries[0]);
ناتج التشغيل Palestine

في المثال السابق قمنا بطباعة العنصر اﻷول من المصفوفة countries

تذكر أن الحاسوب يبدأ العدّ دائماً من صفر وليس من واحد

تذكر مرة أخرى الحاسوب يبدأ العدّ دائماً من صفر وليس من واحد بالتالي العنصر الثالث يعتبره الحاسوب رقم 2 ويجب أن تضع هذا في اﻹعتبار دائماً وإلا ستحدث أخطاء كارثية


var numbers = [10, 20, 30];
console.log(numbers[0]);
console.log(numbers[1]);
console.log(numbers[2]);
ناتج التشغيل 10
20
30

في المثال السابق قمنا بطباعة العنصر اﻷول (مفتاحه 0) ثم طباعة الثاني (مفتاحه 1) ثم طباعة الثالث من المصفوفة [10, 20, 30]

var numbers = [10, 20, 30];
var result = numbers[0] * numbers[1];
console.log(result);
ناتج التشغيل 200

في المثال السابق قمنا بطباعة حاصل ضرب العنصرين اﻷول والثاني من المصفوفة numbers.. 10 * 20 = 200

لاحظ أننا أنشأنا متغير اسميناه result وتساوي قيمته حاصل ضرب العنصر اﻷول numbers[0] والعنصر الثاني numbers[1]

الوصول ديناميكياً لعناصر المصفوفة

يمكن وضع أي تعبير برمجي (expression) بين [] وليس مجرد عدد، جرب اﻷمثلة التالية:

var numbers = [10, 20, 30];
var i = 0;
console.log(numbers[i]);
console.log(numbers[i+1]);
console.log(numbers[i+2]);
ناتج التشغيل 10
20
30

عندما يمر المفسر على الكود numbers[i] سيقوم أولاً بتنفيذ التعبير الموجود داخل اﻷقواس ثم استخدام ناتج التعبير كمفتاح، فبما أن i تساوي 0 إذن سيعتبر المفسر أن numbers[i] تساوي numbers[0] وكذلك إن قلنا numbers[1+1] سيقوم المفسر أولاً بتنفيذ عملية الجمع بين اﻷقواس ثم يتعامل كأنك كتبت numbers[2]

تعديل عناصر المصفوفة

كما تعلمنا في درس المتغيرات أننا يمكننا الوصول للمتغير بإسمه، ويمكننا إرفاق قيمة له وتعديل قيمته باستخدام علامة = مثال: i = 10 فهنا في المصفوفات نفس الشيء، يمكننا الوصول لعنصر من المصفوفة عن طريق اسم المصفوفة ومفتاح العنصر، وكذلك يمكننا ارفاق قيمة أخرى لهذا العنصر باستخدام العلامة =

var numbers = [10, 20, 30];
console.log(numbers[0]);
numbers[0] = 15;
console.log(numbers[0]);
ناتج التشغيل 10
15

إضافة عنصر غير موجود إلى مفتاح معين

جرب الوصول لعنصر غير موجود، مثلاً العنصر الرابع من المصفوفة [10, 20, 30] ستجد أن الناتج undefined أي غير معرف، وفي معظم لغات البرمجة اﻷخرى سيعطي المفسر خطأ،

جرب بنفس طريقة تعديل العناصر تعديل عنصر بمفتاح غير موجود، مثلاً المصفوفة فيها 3 عناصر، جرب تعديل العنصر الرابع numbers[3] وستجد أن المفسر يقوم بإرفاق القيمة لهذا العنصر!

مثال إضافة عنصر رابع للمصفوفة:

var numbers = [10, 20, 30];
console.log(numbers[3]);
numbers[3] = 40;
console.log(numbers[3]);
ناتج التشغيل undefined
40

المثال السابق يطبع العنصر الرابع (غير موجود) ثم يقوم بإرفاق قيمة له وطباعته مرة أخرى فيطبع قيمته وهي 40

مثال آخر لتعديل قيمة العنصر الثامن في المصفوفة!

var numbers = [10, 20, 30];
numbers[8] = 80;
console.log(numbers[8]);
console.log(numbers);
ناتج التشغيل 80
[10, 20, 30, , , , , , 80]

في المثال السابق هناك قيم فارغة، مثلاً العنصر الرابع والخامس .. أما العنصر الثامن قيمته 80

يمكن استخدام هذه الطريقة لإضافة عنصر لمفتاح معين، أما إضافة عنصر لآخر أو أول المصفوفة سندرسهم بعد قليل

دوال وخصائص المصفوفة (methods and properties)

للمصفوفات دوال مدمجة باللغة، فكل لغة برمجة تقدم دوال وخصائص تساعدك في التحكم بالمصفوفة والتعديل عليها، سندرس منها الدوال اﻷساسية والموجودة في كل اللغات تقريباً لكن في المراحل المتقدمة ستعرف المزيد من الدوال، وربما تجد دوال متقدمة ودوال موجودة في لغات وفي لغات أخرى ﻻ.

معرفة عدد عناصر المصفوفة (طولها)

هناك خاصية في المصفوفات يمكننا استخدامها لمعرفة عدد عناصر المصفوفة! وهي الخاصية length وتعني بالعربية "طول" وباستخدامها يمكننا بسهولة معرفة طول المصفوفة

هذه الخاصية هي الحل لمشكلة عدد مستخدمي البرنامج التي ذكرناها في أول الدرس

var numbers = [10, 20, 30];
console.log(numbers.length);
ناتج التشغيل 3

ستختلف طريقة كتابتها من لغة ﻷخرى، في جافاسكريبت مثلاً نستخدم النقطة "." ثم نضع اسم الخاصية length أما في لغات أخرى ربما تكون دالة وليست خاصية، مثلاً الدالة len() أو count() وهكذا، لكن المفهوم واحد بين كل اللغات

استخدام حقيقي لطول المصفوفة

يمكنك استخدام طول المصفوفة لحل المشكلة المذكورة في بداية الدرس "معرفة عدد مستخدمي البرنامج"، أيا كان العدد وأيا كان تغير أم ﻻ، فمثلاً إن كنت مستقبلاً مبرمج مواقع وتقوم ببرمجة لوحة تحكم للموقع، يجب أن يظهر في لوحة التحكم احصائيات منها عدد المستخدمين، هنا ما تحتاجه فقط هو مصفوفة فيها المستخدمين ثم يمكنك الوصول لطول المصفوفة .length بسهولة لتعرف عدد المستخدمين برمجياً.

تعديل العنصر اﻷخير في المصفوفة بدون معرفة مفتاحه

يمكننا باستخدام طول المصفوفة تعديل العنصر اﻷخير بدون معرفة مفتاحه! كيف؟ فكرّ فيها قليلاً... المصفوفة عندما تكون من ثلاثة عناصر كم يكون مفتاح العنصر اﻷخير؟ بالتأكيد 2 ﻷن الحاسوب يبدأ عد من الصفر، كذلك إن كانت المصفوفة من 5 عناصر كم يكون مفتاح العنصر اﻷخير؟ 4 إذن مفتاح العنصر اﻷخير هو طول المصفوفة مطروحا منه واحد! أي array.length - 1

var numbers = [10, 20, 30];
console.log( numbers[ numbers.length-1 ] );
numbers[numbers.length-1] = 35;
console.log( numbers[ numbers.length-1 ] );
ناتج التشغيل 30
35

وضعنا مسافات بين اﻷقواس وما بداخلها لتكون القراءة سهلة، لكن يمكنك حذفها


عندما يمر المفسر على numbers[numbers.length-1] فإنه يقوم بتفسير التعبير الموجود بين اﻷقواس أولاً ثم استخدام الناتج كمفتاح، ففي حالتنا يكون ناتج التعبير يساوي 3-1 يساوي 2 إذن يتعامل المفسر مع الكود على أنه numbers[2]

إضافة عنصر جديد للمصفوفة

يمكنك استخدام الدالة push() المدمجة في جافاسكريبت لإضافة عنصر جديد إلى المصفوفة (إلى آخرها) ويوضع العنصر الجديد كمُدخل للدالة بين اﻷقواس

var numbers = [10, 20];
console.log(numbers);
numbers.push(30);
console.log(numbers);
ناتج التشغيل [10, 20]
[10, 20, 30]
تمرين

جرب إضافة عنصر إلى المصفوفة باستخدام length بدلاً من الدالة الجاهزة push()

حذف عنصر من المصفوفة

يمكنك حذف العنصر اﻷخير من المصفوفة بسهولة باستخدام الدالة pop() وستجد هذه الدالة في معظم لغات البرمجة، أحياناً بنفس الإسم وأحيانا يتغير...

var numbers = [10, 20, 30];
numbers.pop();
console.log(numbers);
ناتج التشغيل [10, 20]

الوصول لكل عناصر المصفوفة

الوصول لكل عناصر المصفوفة عملية مهمة جداً عملياً وهي من أهم ما ستحتاجه عندما تتعامل مع المصفوفات، فمثلاً قمنا بتخزين المنشورات في مصفوفة… واﻵن نريد مثلاً أن نصل لكل منشور لنعرضه للمستخدم، كيف نتمكن من تنفيذها؟ أو مثلاً في مشكلة الدول المتعددة التي ذكرناها أول الدرس، نريد الوصول لكل الدول الموجودة في المصفوفة لنتحقق من دولة المستخدم هل هي تساوي دولة من الدول الموجودة في المصفوفة فنمسح له أم ﻻ!

استنتاج حل مشكلة الوصول لكل العناصر

اﻵن لدينا مشكلة برمجية، وهي أننا نريد الوصول لكل عناصر المصفوفة، ولكن هناك بعض اﻷمور التي تعلمناها ستساعدنا في حل المشكلة، حاول استنتاج الحل منها:

  • الحلقات التكرارية: تعلمناها سابقاً في درس الحلقات التكرارية وبها يمكننا تكرار تنفيذ كتلة من اﻷوامر لعدد معين من المرات، أو لحين عدم تحقق شرط الحلقة، فبالتالي يمكننا مثلاً إنشاء متغير عدّاد اسمه i يبدأ من 0 وتتكرر الحلقة 5 مرات مثلاً أو أي عدد من المرات.
  • طول المصفوفة: تعلمنا في هذا الدرس الحصول على طول المصفوفة باستخدام الخاصية length
  • الوصول لعناصر المصفوفة بالمفتاح index: تعلمنا في هذا الدرس الوصول لأي عنصر من عناصر المصفوفة باستخدام مفتاحه index، وهذا المفتاح يكون ترتيبه
تمرين

فكر كيفية الوصول لكل عناصر المصفوفة باستخدام ما ذكرنا في النقاط السابقة



فكرة حل مشكلة الوصول لكل عناصر المصفوفة

يمكننا الوصول لكل عناصر المصفوفة باستخدام الحلقات التكرارية عن طريق:

  • إنشاء حلقة تكرارية تتكرر عدد من المرات يساوي طول المصفوفة: فإن كانت المصفوفة تتكون من 10 عناصر سنقوم بإنشاء حلقة تكرارية تتكرر 10 مرات
  • الحلقة التكرارية تبدأ من صفر: ﻷن أول عنصر في المصفوفة مفتاحه 0، بالتالي متغير العداد للحلقة التكرارية i مثلاً سيساوي صفر
  • نستخدم متغير العداد كمفتاح للوصول لعناصر المصفوفة داخل كتلة أوامر الحلقة: بما أن الحلقة التكرارية ستبدأ من صفر، وتتكرر بعدد عناصر المصفوفة، إذن إن كانت المصفوفة من 10 عناصر ستتكرر الحلقة 10 مرات وفي كل دورة تتغير قيمة متغير العداد، مثلاً في أول دورة يكون 0 ثم 1 ثم 2، وبالتالي يمكننا استخدامه array[i] للوصول للعنصر الحالي في المصفوفة، بالتالي في الدورة اﻷولى ستكون قيمة متغير العداد i تساوي 0، إذن array[i] تساوي العنصر اﻷول من المصفوفة، وهكذا مع كل دورة من دورات الحلقة التكرارية يمكننا الوصول لعنصر!

مثال الوصول لكل عناصر المصفوفة

var countries = ["Palestine", "Syria", "Egypt"];
var i = 0;
while (i < countries.length){
  console.log( countries[i] );
  i = i + 1;
}
ناتج التشغيل Palestine
Syria
Egypt

الكود السابق يقوم بطباعة كل عنصر من عناصر المصفوفة منفرداً

لاحظ أن الشرط i < countries.length نستخدم فيه العلامة أقل من <، ولو استخدمنا العلامة <= سيتحقق الشرط أيضاً مع 3 وبالتالي لن يجد المفسر العنصر countries[3] ﻷن هذا هو العنصر الرابع، والمصفوفة تتكون من ثلاثة عناصر فقط.


ويمكن أيضاً استخدام الشرط i <= countries.length - 1 سيؤدي نفس الغرض! ﻷنه سيكون i <= 2 بالتالي سيتحقق مع 2 ولن يتحقق مع 3 ﻷن 3 أكبر من 2، فأياً كان الشرط المستخدم وأيا كانت الطريقة، المهم أنك فهمت خوارزمية الحل!

حل مشكلة الدول المتعددة (مثال)

اﻵن يمكننا باستخدام ما تعلمنا حل مشكلة الدول المتعددة التي ذكرناها في أول الدرس، فيمكننا اﻵن وضع عدد من الدول في مصفوفة وتكون هذه الدول هي الدول المسموح بها، وطباعة "أهلاً بك في البرنامج" إن كانت دولة المستخدم من الدول المسموح بها أو طباعة "البرنامج غير متوفر في دولتك" إن كان دولة المستخدم ليست من الدول المسموح بها.

سنستخدم الشروط if للتحقق

var userCountry = "Syria"; // Enter user country here
var countries = ["Palestine", "Syria", "Egypt"];
var allowed = false;

var i = 0;
while (i < countries.length){
  if( countries[i] == userCountry ){
    allowed = true;
  }
  i = i + 1;
}

if (allowed){
  console.log("أهلاً بك في البرنامج");
}else{
  console.log("البرنامج غير متوفر في دولتك");
}
ناتج التشغيل أهلاً بك في البرنامج

جرب اﻵن تغيير قيمة userCountry إلى أي دولة أخرى، مثلاً USA سيقوم المفسر بطباعة "غير مسموح لدولتك ..." ﻷن الدولة ليست من الدول المسموح بها، الموجودة في المصفوفة

تحسين برنامج الدول المسموح بها بالدوال

اﻵن نريد استخدام الدوال في تحسين وتسهيل استخدام البرنامج السابق، حتى نتمكن من استدعاء الدالة وإدخال دولة المستخدم كمُدخل للدالة والدالة تتحقق وتطبع هل الدولة مسموح بها أم ﻻ!

ارجع إلى درس الدوال للمراجعة أو لتعلم الدوال إن كانت جديدة عليك

هذا المثال يعتمد على معرفتك بالدوال، وليس له علاقة بدرس اليوم... فقط تطبيق على الدوال

function countryIsAllowed(userCountry){
  var countries = ["Palestine", "Syria", "Egypt"];
  var allowed = false;

  var i = 0;
  while (i < countries.length){
    if( countries[i] == userCountry ){
      allowed = true;
    }
    i = i + 1;
  }

  if (allowed){
    console.log("أهلاً بك في البرنامج");
  }else{
    console.log("البرنامج غير متوفر في دولتك");
  }
}

countryIsAllowed("Egypt");
countryIsAllowed("USA");
countryIsAllowed("England");
countryIsAllowed("Palestine");
countryIsAllowed("Syria");
ناتج التشغيل

أهلاً بك في البرنامج
البرنامج غير متوفر في دولتك
البرنامج غير متوفر في دولتك
أهلاً بك في البرنامج
أهلاً بك في البرنامج

في المثال السابق أنشأنا دالة، وقمنا باستدعاءها 5 مرات لتنفيذها على 5 دول مختلفة.

تمارين على المصفوفات

تمرين 1

قم بكتابة دالة printInLine(array) تأخذ مصفوفة كمُدخل وتقوم بطباعة كل عناصرها في سطر واحد وتفصل بينهم بمسافة " ". مثلاً printInLine([1, 2, 3]) تطبع سطر يحتوي على 1 2 3، و printInLine(["Palestine", "Syria"]) تطبع سطر يحتوي على Palestine Syria

تمرين 2

قم كتابة دالة اسمها filter تأخذ مصفوفة من اﻷعداد كمُدخل: filter(numbers)، وتقوم بطباعة مصفوفة تحتوي على اﻷعداد اﻷقل من 10 من المصفوفة اﻷولى numbers، مثلاً الدالة filter([1, 3, 7, 15, 12, 14]) تقوم بطباعة [1, 3, 7] فقط.

تمرين 3

قم بكتابة دالة sum(numbers) تأخذ مصفوفة من اﻷعداد كمُدخل وتقوم بطباعة مجموع كل اﻷعداد الموجودة في المصفوفة مثلاً: sum([5, 10, 10, 5]) تقوم بطباعة 30

تمرين متقدم

قم بكتابة دالة largest(numbers) تأخذ مصفوفة من اﻷعداد كمُدخل وتقوم بطباعة العدد اﻷكبر مثلاً: largest([5, 10, 17, 5]) تقوم بطباعة 17

المساهمين

وجدت خطأ أو تريد المساهمة في محتوى الدرس؟ عدل الصفحة على Github