مسائل حول الأراي واستخدام الـ Loops

السلام عليكم ورحمة الله وبركاته

وقت القراءة: ≈ 10 دقائق

المقدمة

الأراي كما شرحناها سابقًا هي نوع من أنواع هياكل البيانات التي تستخدم لتخزين مجموعة من القيم والبيانات المرتبطة ببعضها تحت مسمى واحد

int arr[5] = {1, 2, 3, 4, 5};

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

والأراي تعد من أهم الأمور التي ستستخدمها في مسيرتك البرمجية وستساعدك في حل العديد من المشكلات والمسائل البرمجية
على سبيل المثال معك أراي تحتوي عن مجموعة من الأرقام، أريدك أن:

ولكل هذه المسائل سنقوم بحلها في هذا الدرس وسنتعرف على كيفية استخدام الـ Loops لحل هذه المسائل
في الحقيقة استخدام الـ Loops مع الأراي أمر شائع ومن أهم الأمور التي يجب أن تنقنها
لأنك في كل مرة تريد القيام بعملية معينة في الأراي ستحتاج إلى الـ Loops

طباعة عناصر الأراي باستخدام الـ Loop

لنفترض أن لدينا أراي تحتوي على مجموعة من الأرقام العشوائية بهذا الشكل

int arr[10] = {12, 45, 7, -23, 59, 0, -300, 67, -1, 5};

وقلت لك ببساطة أن تطبع لي جميع العناصر في الأراي
ما كنا نقوم به هو أن نستخدم الـ index للوصول إلى كل عنصر في الأراي ونطبعه

cout << arr[0] << '\n'; // 12
cout << arr[1] << '\n'; // 45
cout << arr[2] << '\n'; // 7
cout << arr[3] << '\n'; // 23
cout << arr[4] << '\n'; // -9
// ... etc.

لكن هذا ليس حل جيد كما تلاحظ لأنه إذا كانت الأراي تحتوي على عدد كبير من العناصر مثلًا 100 فإن الأمر سيكون متعبًا ومكررًا

لذلك نستخدم الـ Loop هنا لتساعدنا على المرور على كل عناصر الأراي
أنت كل ما تحتاجه هو أن تجعل الـ index يتغير من 0 إلى n-1 حيث n هو عدد العناصر في الأراي

int arr[10] = {12, 45, 7, -23, 59, 0, -300, 67, -1, 5};

int i = 0;
while (i < 10) {
    cout << arr[i] << '\n';
    i++;
}

هنا قمنا بإنشاء متغير i ليمثل لنا الـ index وبدأنا من 0 ثم في كل مرة نقوم بطباعة العنصر arr[i] ونزيد قيمة i بواحد عن طريق i++
هكذا في كل لفة سيتم طباعة عنصر من الأراي بالترتيب حتى نصل إلى نهاية الأراي
لأن الـ i يبدأ من 0 ثم نطبع arr[0] ثم نزيد i ليصبح 1 ثم نطبع arr[1] وهكذا حتى نصل إلى أخر index وهو الشرط i < 10 الذي يوقف الـ while

هنا استخدمنا الـ while للقيام بذلك ولكن يمكنك استخدام الـ for أيضًا
وهذا هو الكود بالـ for

int arr[10] = {12, 45, 7, -23, 59, 0, -300, 67, -1, 5};

for (int i = 0; i < 10; i++) {
    cout << arr[i] << '\n';
}

طباعة عناصر الأراي بشكل عكسي

إذا أردنا طباعة الأراي بشكل عكسي بمعنى أن نبدأ من العنصر الأخير وننتهي بالعنصر الأول
يمكننا استخدام الـ loop بنفس الطريقة لكن نجعل المتغير i الذي يمثل index يبدأ من الـ index الخاص بالعنصر الأخير في الأراي وننقصه بدلًا من زيادته حتى يصل إلى 0

int arr[10] = {12, 45, 7, -23, 59, 0, -300, 67, -1, 5};

int i = 9;
while (i >= 0) {
    cout << arr[i] << '\n';
    i--;
}

لاحظ أننا هنا بدأنا من 9 لأن أخر index في الأراي الذي يحتوي على 10 عناصر هو 9 وليس كما تعرف
ثم لاحظ أن الشرط هنا هو i >= 0 وهذا يعني أن الـ loop ستستمر طالما i أكبر من أو تساوي الـ 0
وبالطبع ننقص i في كل لفة بواحد حتى نصل إلى 0

هكذا في أول لفة قيمة i ستكون 9 ثم سنطبع arr[9] ثم ننقص قيمة i
الآن في اللفة الثانية قيمة i تساوي 8 لذا سنطبع arr[8] ثم ننقص قيمة i ليصبح 7
ونستمر هكذا حتى نصل إلى الـ 0 وننتهي من الـ loop


بالطبع يمكنك استخدام الـ for بدلًا من الـ while للقيام بنفس العملية

int arr[10] = {12, 45, 7, -23, 59, 0, -300, 67, -1, 5};

for (int i = 9; i >= 0; i--) {
    cout << arr[i] << '\n';
}

طباعة عناصر الأراي بناءً على شرط معين

الآن لنفترض أن الأراي تحتوي على مجموعة من الأرقام العشوائية ونريد طباعة الأرقام السالبة فقط
يمكننا استخدام الـ loop مع الشرط if للقيام بذلك

int arr[10] = {12, 45, 7, -23, 59, 0, -300, 67, -1, 5};

for (int i = 0; i < 10; i++) {
    if (arr[i] < 0) {
        cout << arr[i] << '\n';
    }
}

هنا قمنا بإنشاء الـ loop وفي كل لفة نتحقق من قيمة العنصر arr[i] إذا كانت أقل من الـ 0 نطبعها
وهكذا سيتم طباعة الأرقام السالبة فقط


بالطبع يمكنك تغير الشرط ليطبع لك الأرقام الموجبة فقط أو الأرقام الزوجية أو الفردية أو الأرقام التي تقبل القسمة على 3 أو أي شرط تريده

يمكنك تجربة ذلك بنفسك والتعديل على الشرط حسب ما تريد

إيجاد أكبر عنصر في الأراي

فكر معي في هذه المسألة، كيف يمكننا إيجاد أكبر عنصر في الأراي ؟
يمكنك المرور على كل عناصر الأراي ويمكنك عمل شرط معين
لكن ما هو هذا الشرط ؟ هل يمكنك تفكير فيه ؟

نحتاج لشرط يقول لنا أن الرقم الذي نحن فيه الآن هو أكبر من الأرقام التي مررنا عليها حتى الآن

بمعنى أننا لدينا أراي بهذا الشكل

int arr[10] = {12, 45, 7, -23, 59, 0, -300, 67, -1, 5};

الآن نحن نستطيع عمل loop يمر على كل العناصر
في اللفة الأولى نحن نكون عن العنصر 12 وفي اللفة الثانية نكون عن العنصر 45 وفي اللفة الثالثة نكون عن العنصر 7 وهكذا
نحتاج لشيء يخبرنا أن العنصر الذي نحن فيه الآن هو أكبر رقم ممر عليه حتى الآن
بالتالي نحتاج لمتغير يحتفظ بأكبر رقم مررنا عليه حتى الآن ونقارنه بكل عنصر جديد نمر عليه

بالتالي عندما نقف على العنصر 12 في اللفة الأولى نقول أن 12 هو أكبر رقم وجددناه حتى الآن
ثم نمر على العنصر 45 في اللفة الثانية ونقارنه بالـ 12 سنجد أن 45 أكبر من 12
لذا سنقول أن 45 هو أكبر رقم وجددناه لذا سنقوم بتغيير المتغير الذي كان يحتفظ بأكبر رقم ونجعله يحتفظ بـ 45
ثم نمر على العنصر 7 في اللفة الثالثة ونقارنه بالـ 45 سنجد أن 45 يظل أكبر من 7 لذا لن نقوم بتغيير المتغير الذي يحتفظ بأكبر رقم وجدناه
وهكذا حتى نصل إلى نهاية الأراي

لنكتب الكود ثم نقوم بشرحه وتحليله في جدول جميل

int arr[10] = {12, 45, 7, -23, 59, 0, -300, 67, -1, 5};

// ننشئ متغير ليحتفظ بأكبر عنصر ونفترض أن العنصر الأول هو الأكبر
int max_value = arr[0];

// نبدأ من العنصر الثاني لأن الأول افترضنا أنه الأكبر
for (int i = 1; i < 10; i++) {
    if (arr[i] > max_value) {
        max_value = arr[i];
    }
}

أهم جزء هنا هو جزء الـ if حيث نقوم بالتحقق إذا كان العنصر الذي نحن فيه الآن arr[i] أكبر من قيمة max_value
إذا كان العنصر الحالي أكبر من max_value فسنقوم بتحديث قيمة max_value لتكون العنصر الحالي
وإذا لم يكن العنصر الحالي أكبر من max_value فلن نقوم بتحديث قيمة max_value وسنستمر في الـ loop حتى نصل إلى نهاية الأراي

قيمة i قيمة arr[i] قيمة max_value الشرط arr[i] > max_value النتيجة
1 45 12 الشرط 45 > 12
سيعطي true
إذًا قم بتحديث قيمة max_value
max_value = 45
2 7 45 الشرط 7 > 45
سيعطي false
لن نقوم بتحديث القيمة
3 -23 45 الشرط -23 > 45
سيعطي false
لن نقوم بتحديث القيمة
4 59 45 الشرط 59 > 45
سيعطي true
إذًا قم بتحديث قيمة max_value
max_value = 59
5 0 59 الشرط 0 > 59
سيعطي false
لن نقوم بتحديث القيمة
6 -300 59 الشرط -300 > 59
سيعطي false
لن نقوم بتحديث القيمة
7 67 59 الشرط 67 > 59
سيعطي true
إذًا قم بتحديث قيمة max_value
max_value = 67
8 -1 67 الشرط -1 > 67
سيعطي false
لن نقوم بتحديث القيمة
9 5 67 الشرط 5 > 67
سيعطي false
لن نقوم بتحديث القيمة

بهذا الشكل سنحصل على أكبر عنصر في الأراي وهو 67


بالطبع يمكنك استخدام نفس الطريقة لإيجاد أصغر عنصر في الأراي
أو إيجاد أكبر رقم سالب أو أصغر رقم فردي أو أي شيء تريده
هذه أفكار ومسائل يمكنك تطبيقها بنفس الطريقة وستساعدك في فهم كيفية استخدام الـ Loops مع الأراي بشكل أفضل
وستساعدك في حل العديد من المسائل البرمجية وستوسع أفكارك

حساب مجموع عناصر الأراي

الآن لنفكر في كيفية حساب مجموع عناصر الأراي
أولاً نحتاج لمتغير يحتفظ بالمجموع الكلي تبدأ قيمته بـ 0
ثم نمر على كل عنصر في الأراي وفي كل لفة نجمع قيمة العنصر الذي نقف عليه بالمتغير الذي يحتفظ بالمجموع الكلي

int arr[10] = {12, 45, 7, -23, 59, 0, -300, 67, -1, 5};

// ننشئ متغير ليحتفظ بالمجموع الكلي وبالطبع قيمته ستكون هي 0 لأننا سنجمع عليه
int sum = 0;

// نمر على كل عناصر الأراي وجمع قيمة كل عنصر إلى المتغير بشكل مباشر
for (int i = 0; i < 10; i++) {
    sum += arr[i];
}

هنا قمنا بإنشاء متغير sum ليحتفظ بالمجموع الكلي وبدأنا قيمته بـ 0
ثم نمر على كل عنصر في الأراي وفي كل لفة نقوم بجمع قيمة العنصر arr[i] بالمتغير sum
الأمر بهذه البساطة حتى أنه أبسط من المسألة السابقة لأننا لا نحتاج لشرط معين هنا فقط نقوم بجمع بشكل مباشر في كل لفة

قيمة i قيمة arr[i] قيمة sum قبل الإضافة قيمة sum بعد الإضافة
sum += arr[i]
0 12 0 12
1 45 12 57
2 7 57 64
3 -23 64 41
4 59 41 100
5 0 100 100
6 -300 100 -200
7 67 -200 -133
8 -1 -133 -134
9 5 -134 -129

بهذا الشكل سنحصل على مجموع عناصر الأراي وهو -129

البحث عن عنصر معين في الأراي

حسنًا، الآن لنفكر في كيفية البحث عن عنصر معين في الأراي
فكر معي في كيفية البحث عن عنصر معين في الأراي ؟
سنفترض أن العنصر الذي نبحث عنه هو 59 نريد أن نعرف ما إذا كان هذا العنصر موجود في الأراي أم لا
وإذا كان موجودًا نريد أن نعرف موقعه في الأراي، أي الـ index الذي يتواجد فيه
وإذا لم يكن موجودًا نريد أن تطبع جملة تقول أن العنصر غير موجود

كيف يمكننا القيام بذلك ؟

حسنًا، أولًا سيكون لدينا متغير يدعى target وهو العنصر الذي نبحث عنه وهو من معطيات المسألة وهو 59
الآن نستطيع المرور على كل عناصر الأراي وفي كل لفة نقوم بالتحقق إذا كان العنصر arr[i] يساوي target أم لا

int arr[10] = {12, 45, 7, -23, 59, 0, -300, 67, -1, 5};

// العنصر الذي نبحث عنه
int target = 59;

// نمر على كل عناصر الأراي ونقارن كل عنصر بالعنصر المطلوب
for (int i = 0; i < 10; i++) {
    if (arr[i] == target) {
        cout << "We found the target, and its index is: " << i << '\n';
        break;
    }
}

هنا لدينا متغير target الذي يحتفظ بالعنصر الذي نبحث عنه وهو 59
نحن بكل بساطة نمر على كل عناصر الأراي وفي كل لفة نقارن قيمة الـ arr[i] بقيمة target
هل قيمة arr[i] تساوي قيمة target أم لا ؟

إذا كانت تساوي فسنقوم بطباعة جملة تقول أننا وجدنا العنصر وموقعه في الأراي
وبعد ذلك سنقوم بإيقاف الـ loop بواسطة الأمر break لأننا وجدنا العنصر ولا داعي للمتابعة
لاحظ أننا استخدمنا الـ break لإيقاف الـ loop بمجرد العثور على العنصر المطلوب
ولو لم نستخدم الـ break فسيستمر الـ loop حتى نصل إلى نهاية الأراي برغم من أننا وجدنا العنصر

هنا لدينا مشكلة صغير وهي ماذا لو لم نجد العنصر المطلوب ؟
ألم نقل أننا نريد أن تطبع جملة تقول أن العنصر غير موجود ؟ كيف يمكننا القيام بذلك ؟

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

هنا يمكننا عمل متغير يسمى found ويكون من نوع bool بالتالي يمكنه أن يكون true أو false
لنجعل قيمته الافتراضية false ونقوم بتغيير قيمته إلى true إذا وجدنا العنصر المطلوب

int arr[10] = {12, 45, 7, -23, 59, 0, -300, 67, -1, 5};

// العنصر الذي نبحث عنه
int target = 999; // رقم غير موجود في الأراي

// متغير ليخبرنا إذا وجدنا العنصر المطلوب أم لا
bool found = false;

// نمر على كل عناصر الأراي ونقارن كل عنصر بالعنصر المطلوب
for (int i = 0; i < 10; i++) {
    if (arr[i] == target) {
        cout << "We found the target, and its index is: " << i << '\n';
        found = true; // لنعرف أننا وجدنا العنصر true نغير قيمته إلى
        break;
    }
}


// نتحقق هل وجدنا العنصر أم لا
if (found == false) {
    cout << "The target is not found in the array\n";
}

لاحظ أننا هنا قمنا بإنشاء متغير found من نوع bool وقيمته الافتراضية هي false
ثم نمر على كل عناصر الأراي وفي كل لفة نقوم بالتحقق إذا كان العنصر arr[i] يساوي target
إذا تحقق الشرط نقوم بطباعة جملة تقول أننا وجدنا العنصر ونغير قيمة found إلى true
وإذا لم يتحقق فسنستمر في الـ loop حتى ننتهي من الأراي وستظل قيمة found تساوي false قيمته الافتراضية

ثم في نهاية الـ loop نتحقق إذا كانت قيمة found تساوي false أي أنها ظلت كما هي ولم تتغير إلى true فهذا يعني أننا لم نجد العنصر المطلوب
لذا سنقوم بطباعة جملة تقول أن العنصر غير موجود في الأراي

for-each loop

حسنًا تعرفنا سابقًا عن الـ for والـ while والـ do while وكيفية استخدامها ورأينا بعض الأمثلة مع الأراي وغيرها
وقلنا أنها تساعدنا في تكرار العمليات والتحكم فيها والقيام بعمليات معينة في كل لفة
وقلنا أن هناك أدوات أخرى تساعدنا في الـ Loops مثل الـ recursion والـ for-each loop وغيرها

الآن سنتعرف على الـ for-each loop
أولًا هي لها العديد من الأسماء والمتشابهات والنسخ مثل الـ for-each loop والـ for in loop والـ for of loop وغيرها الكثير بحسب اللغة وكل لغة لها طريقتها الخاصة في بناء الـ for-each loop ولكن الفكرة العامة واحدة

الـ for-each loop تساعدنا في تكرار العناصر في الأراي بدون الحاجة للتحكم في الـ index
لأنها تقوم بالمرور على الأراي وتعطيك في كل لفة قيمة العنصر مباشرةً بدون الحاجة للـ index

لنرى مثال بسيط على الـ for-each loop في الـ C++

int arr[10] = {12, 45, 7, -23, 59, 0, -300, 67, -1, 5};

for (int element : arr) {
    cout << element << '\n';
}

هنا قمنا بإنشاء الـ for-each loop وفي كل لفة سيتم إعطائك قيمة العنصر مباشرةً
لاحظ شكلها البسيط والسريع في كتابة كود، وكما تلاحظ نحن فقط ننشيء متغير سيمثل كل عنصر من عناصر الأراي وهو element ويمكنك بالطبع تسميته كما تشاء
ثم ستقوم الـ loop كالعادة بالمرو كل عنصر عنصر في كل لفة وتخزين العنصر الي تقف عليه حاليًا في هذا المتغير الذي انشأناه

لو أردنا كتابة نفس الكود بالـ for العادي سيكون بهذا الشكل

int arr[10] = {12, 45, 7, -23, 59, 0, -300, 67, -1, 5};

for (int i = 0; i < 10; i++) {
    cout << arr[i] << '\n';
}

هنا نرى أن الـ for-each loop تساعدنا في تقليل الكود وتبسيطه وتجعله أكثر وضوحًا وسهولة في القراءة
لكنها كما لاحظت مرتبطة بشكل أساسي بالأراي لذا استخداماتها محصورة في الأراي فقط وما يشابهها (وستعرف ما أقصده لاحقًا)
وهي لا تعطيك الـ index لذا إذا كنت بحاجة للـ index فعليك استخدام الـ for العادي


وبما أن الـ string يعتبر أراي من الـ char فيمكننا استخدام الـ for-each للمرور على كل حرف من حروف الـ string

string name = "Ahmed";

for (char character : name) {
    cout << character << '\n';
}

لاحظ هنا أننا جعلنا المتغير الذي سيحتفظ بكل حرف في كل لفة نوعه char
أظنك تعرف السبب ولا داعي للتفسير مجددًا


بالطبع يمكنك استخدام الـ for-each loop مع الأراي لتنفيذ العديد من الأمور المتعلقة بالأراي
مثل البحث عن عنصر معين أو حساب مجموع العناصر أو إيجاد أكبر عنصر أو غيرها من الأمثلة التي عرضناها سابقًا

تريد مجموع العناصر في الأراي ؟

int arr[10] = {12, 45, 7, -23, 59, 0, -300, 67, -1, 5};

int sum = 0;

for (int element : arr) {
    sum += element;
}

cout << "The sum of the elements is: " << sum << '\n';

تريد أكبر عنصر في الأراي ؟

int arr[10] = {12, 45, 7, -23, 59, 0, -300, 67, -1, 5};

int max_value = arr[0];

for (int element : arr) {
    if (element > max_value) {
        max_value = element;
    }
}

cout << "The max value is: " << max_value << '\n';

لاحظ أننا هنا نستخدم الـ for-each loop بنفس الطريقة التي استخدمناها في الأمثلة السابقة
لكن لاحظ أننا لا نحتاج للـ index لذا لما نتعب أنفسنا بالتعامل مع الـ for العادية في حين أن الـ for-each loop يقوم بنفس العمل بشكل أسهل وأبسط


أنت هنا تقوم بعملية مفاضلة بين الـ for العادية والـ for-each loop وترى أيهما يناسبك أكثر
هل تريد الـ index حين تريد المرور على الأراي ؟ أم لا تحتاج إليه ؟
إذا كنت لا تحتاج الـ index فالـ for-each loop هي الأفضل لك
لكن إذا كنت بحاجة للـ index فالـ for العادية هي الأفضل لك


بالطبع في لغات مثل الـ TypeScript فيها العدين من النسخ المشابهه للـ for-each loop مثل الـ for of والـ for in وغيرها

let arr: number[] = [12, 45, 7, -23, 59, 0, -300, 67, -1, 5];

for (let element of arr) {
  console.log(element);
}

هنا نرى أننا نستخدم الـ for of في الـ TypeScript وكما تلاحظ أنها مطابقة تمامًا للـ for-each loop في الـ C++
وهي تقوم بنفس العمل وتعطيك قيمة العنصر مباشرةً بدون الحاجة للـ index


في لغة الـ PHP تجد الـ for-each loop تسمى foreach وهي تعمل بنفس الطريقة

$arr = [12, 45, 7, -23, 59, 0, -300, 67, -1, 5];

foreach ($arr as $element) {
    echo $element;
}

في الـ Python تجد الـ for-each loop تسمى for in وهي تعمل بنفس الطريقة

arr = [12, 45, 7, -23, 59, 0, -300, 67, -1, 5]

for element in arr:
    print(element)

لاحظ أنه كما قلت أن كل لغة لها طريقتها الخاصة في بناء الـ for-each loop ولكن الفكرة العامة واحدة
قد يختلف الاسم والشكل وطريقة الاستخدام في بعض الأحيان ولكن الفكرة العامة واحدة والأساس واحد

هل هذا كل شيء ؟

بالطبع لا هذه فقط بعض الأمثلة البسيطة التي توضح لك كيفية استخدام الـ Loops مع الأراي
مع بعض الأفكار والمسائل الجميله التي قد تصادفك في مسيرتك البرمجية
هدفي هنا فقط هو توسيع أفكارك ومساعدتك في فهم كيفية استخدام الـ Loops مع الأراي
وكيفية حل بعض المسائل البرمجية والتفكير في ايجاد حل وتطبيقه