You are on page 1of 8

‫جامعة ادلب‬

‫كلية الهندسة المعلوماتية‬


‫السنة الثانية‪ -‬مادة برمجة متقدمة ‪1‬‬

‫المجموعات العادية ‪:‬‬

‫توجد األصناف المعبّرة عن هذه المجموعات ضمن نطاق االسم ‪ System.Collection.‬تلعب‬


‫دورا تنظيميًّا لألصناف‪ .‬من أبرز المجموعات في نطاق االسم هذا هو‬
‫ً‬ ‫نطاقات األسماء‬
‫من‬ ‫ك ّل‬ ‫الصنف ‪ArrayList‬‬ ‫يحقّق‬ ‫‪ArrayList.‬‬ ‫الصنف‬
‫‪ICloneable.‬جميع هذه‬ ‫الواجهات ‪IList‬و ‪ICollection‬و ‪IEnumerable‬و‬
‫تعرف هذه الواجهات العمليّات األساسيّة التي‬
‫الواجهات تقع في مكتبة ‪ FCL‬في إطار عمل دوت نت‪ ،‬حيث ّ‬
‫ينبغي أن يتمتّع بها الصنف ‪ArrayList.‬‬

‫تسمح الكائنات من هذه المجموعة بإضافة أي نوع من العناصر لها‪ ،‬حيث من الممكن أن نضيف عناصر‬
‫من النوع ‪ object.‬يمكن إضافة العناصر إلى هذه المجموعة باستخدام التابع ‪Add‬الذي يقبل وسي ً‬
‫طا‬
‫من النوع ‪object.‬أي أنّنا فعليًّا نستطيع أن نضيف عناصر من أنواع مختلفة لنفس المجموعة‪ .‬أ ّ‬
‫ي‬
‫عنصر تت ّم إضافته سيوضع آخر المجموعة التي هي ذات حجم مرن‪ ،‬فمن الممكن إضافة أي عدد نرغبه‬
‫من العناصر‪ .‬أ ّما إذا أردنا إضافة عنصر إلى مكان محدّد ضمن القائمة‪ ،‬فعلينا استخدام‬
‫األول هو الدليل المراد إدراج العنصر الجديد ضمنه‪ ،‬والثاني‬
‫التابع ‪Insert‬الذي يحتاج إلى وسيطين‪ّ ،‬‬
‫هو العنصر نفسه‪.‬‬

‫انظر البرنامج ‪oop_8‬البسيط التالي‪:‬‬

‫;‪using System.Collections‬‬
‫‪namespace oop_8‬‬
‫{‬
‫‪class Program‬‬
‫{‬
‫)‪static void Main(string[] args‬‬
‫{‬
‫;)(‪ArrayList values = new ArrayList‬‬
‫;)" ‪values.Add("My‬‬
‫;)" ‪values.Add("age:‬‬
‫;)‪values.Add(36‬‬
‫)‪foreach (object item in values‬‬
‫{‬

‫‪1‬‬ ‫م‪.‬بسمة سراقبي‬


‫جامعة ادلب‬
‫كلية الهندسة المعلوماتية‬
‫السنة الثانية‪ -‬مادة برمجة متقدمة ‪1‬‬
‫;)‪Console.Write(item‬‬
‫}‬
‫;)(‪Console.WriteLine‬‬
‫;)(‪Console.ReadKey‬‬
‫}‬
‫}‬
‫}‬

‫استطعنا الحصول على عناصر هذه المجموعة باستخدام حلقة ‪foreach.‬ولكن إذا أردنا الوصول إلى‬
‫عنصر محدّد فحسب‪ ،‬ولنقل أنّه العنصر الثالث (القيمة ‪ )36‬في مثالنا السابق‪ ،‬فيمكن ذلك من خالل الشكل‬
‫التالي‪:‬‬

‫]‪values[2‬‬

‫األول هو ‪ .0‬في الواقع ستكون القيمة التي سنحصل عليها من ]‪ values[2‬هي‬ ‫تذ ّكر دو ًما ّ‬
‫أن دليل العنصر ّ‬
‫قيمة من نوع ‪object‬رغم أنّها في حقيقة األمر تحوي القيمة ‪ 36‬وهي قيمة من نوع ‪int‬بطبيعة‬
‫ي وهو أ ّننا عندما أضفنا القيمة ‪ 36‬إلى المجموعة كان ذلك باستخدام التابع‬
‫الحال‪ .‬السبب في ذلك منطق ّ‬
‫ّ‬
‫المخزنة‬ ‫طا من النوع ‪object.‬إذا أردنا االستفادة من القيمة الفعليّة‬ ‫‪Add‬الذي يقبل وسي ً‬
‫ضمن ]‪ values[2‬فعلينا هنا أن نستخدم عامل التحويل )‪ (int‬على الشكل التالي‪:‬‬

‫;]‪int age = (int) values[2‬‬

‫مالحظة ‪:‬عند تمرير القيمة ‪ 36‬في المثال السابق إلى التابع ‪ Add‬الذي يتوقّع وسيط من نوع‬
‫‪object‬تحدث ظاهرة نسميها التعليب ‪ boxing.‬حيث تُعلَّب القيمة ‪ 36‬ليصبح باإلمكان تمريرها مكان‬
‫وسيط يتطلّب النوع ‪object‬أ ّما عندما نريد استرجاع القيمة الفعليّة فإنّنا نقوم بعمليّة معاكسة تدعى بإلغاء‬
‫التعليب ‪ unboxing‬باستخدام عامل التحويل بين األنواع كما فعلنا بالعبارة البرمجيّة األخيرة‪:‬‬

‫;]‪int age = (int) values[2‬‬

‫هناك العديد من المجموعات األخرى الموجودة ضمن نطاق االسم ‪ ،System.Collection‬ولكن‬


‫لن أتحدّث عنها هنا‪ .‬في الحقيقة إذا أردت نصيحتي حاول ّأال تستخدم المجموعات العاديّة أبدًا! يكمن السبب‬
‫ّ‬
‫سنطلع‬ ‫في ذلك في الفقرة التالية عندما نتحدّث عن المجموعات العموميّة‪ ، generic collection‬حيث‬
‫على مجموعات تشبه إلى ح ٍّ ّد بعيد المجموعات العاديّة الموجودة هنا‪ ،‬ولكنّها عمليّة وأكثر أمانًا‪.‬‬

‫‪2‬‬ ‫م‪.‬بسمة سراقبي‬


‫جامعة ادلب‬
‫كلية الهندسة المعلوماتية‬
‫السنة الثانية‪ -‬مادة برمجة متقدمة ‪1‬‬

‫المجموعات العمومية‬
‫تشبه المجموعات العموميّة ‪ generic collections‬من حيث المبدأ المجموعات العاديّة باستثناء أنّها أكثر‬
‫أم ًنا وأفضل أدا ًء‪ .‬حيث ينبغي تعيين نوع العناصر التي ستتعامل معها المجموعة عند التصريح عنها‪ ،‬فتتعامل‬
‫المجموعة في هذه الحالة مع نوع ُمحدّد‪ .‬من أشهر المجموعات العموميّة هي المجموعة >‪List<T‬وهي‬
‫تعبّر عن القائمة ‪ list.‬قد يبدو الشكل السابق غريبًا ً‬
‫قليال‪ ،‬ولك ّنه في الحقيقة بسيط‪ .‬استبدل الحرف ‪T‬‬
‫ي نوع (صنف) ترغبه وستقبل المجموعة نتيجة لذلك أن يكون عناصرها من هذا النوع‪ .‬تقع المجموعات‬
‫بأ ّ‬
‫العموميّة في نطاق االسم ‪System.Collections.Generic.‬‬

‫سنعدّل البرنامج ‪ OOP_2‬من الدرس السابق الذي كان يسمح بإدخال أسماء ودرجات خمسة طالب فقط‪،‬‬
‫ويخزنها على شكل كائنات ‪Student‬ضمن مصفوفة من النوع ‪[]Student‬وذلك إليجاد مجموع‬ ‫ّ‬
‫الدرجات والمعدّل‪ .‬سنجعل هذا البرنامج يستخدم المجموعة العمومية >‪ ( List<student‬مجموعة يمكن‬
‫لعناصرها تخزين مراجع لكائنات من النوع ‪ )student‬سننشئ البرنامج التالي لهذا الغرض ‪:‬‬

‫;‪using System.Collections.Generic‬‬
‫‪namespace oop_9‬‬
‫{‬
‫‪class Student‬‬
‫{‬
‫} ;‪public string Name { get; set‬‬
‫} ;‪public int Mark { get; set‬‬
‫}‬
‫‪class Program‬‬
‫{‬
‫)‪static void Main(string[] args‬‬
‫{‬
‫;)(>‪List<Student> listStudents = new List<Student‬‬
‫;‪int sum = 0‬‬
‫;‪bool continueCondition = true‬‬
‫;‪int counter = 0‬‬
‫;‪string response‬‬
‫;)"‪Console.WriteLine("Input Students Marks‬‬
‫;)"====================="(‪Console.WriteLine‬‬
‫‪//input loop.‬‬
‫)‪while (continueCondition‬‬
‫{‬

‫‪3‬‬ ‫م‪.‬بسمة سراقبي‬


‫جامعة ادلب‬
‫كلية الهندسة المعلوماتية‬
1 ‫ مادة برمجة متقدمة‬-‫السنة الثانية‬
Student student = new Student();
Console.Write("Input student {0} th name: ",
counter + 1);
student.Name = Console.ReadLine();
Console.Write("Input student {0} th mark: ",
counter + 1);
string tmpMark = Console.ReadLine();
student.Mark = int.Parse(tmpMark);
listStudents.Add(student);
Console.WriteLine();
Console.Write("Add another student? (y/n) : ");
response = Console.ReadLine();
if (response == "n" || response == "N")
{
continueCondition = false;
}
counter++;
}
Console.WriteLine();
Console.WriteLine("Students Marks Table");
Console.WriteLine("====================");
Console.WriteLine("No\tName\tMark");
//calculating sum and display output loop.
for (int i = 0; i < listStudents.Count; i++)
{
sum += listStudents[i].Mark;
Console.WriteLine("{0}\t{1}\t{2}", i + 1,
listStudents[i].Name, listStudents[i].Mark);
}
Console.WriteLine("-------------------");
Console.WriteLine("Sum\t\t{0}", sum);
Console.WriteLine("Average\t\t{0}", sum /
(double)listStudents.Count);
Console.ReadKey();
}
}
}

4 ‫بسمة سراقبي‬.‫م‬
‫جامعة ادلب‬
‫كلية الهندسة المعلوماتية‬
‫السنة الثانية‪ -‬مادة برمجة متقدمة ‪1‬‬

‫لقد أجرينا هنا بعض التحسينات‪ .‬بدأنا البرنامج بالتصريح عن المتغيّر ‪listStudents‬من‬
‫النوع >‪List<Student‬وإنشاء كائن من هذا النوع وإسناده لهذا المتغيّر‪ .‬تقبل المجموعة‬
‫العموميّة >‪ List<Student‬بتخزين كائنات من النوع ‪Student‬ضمنها‪ .‬الحظ أنّنا لم نحدّد عدد‬
‫بدال من حلقة ‪for‬‬ ‫الكائنات مسبقًا (مع أنّه يمكن ذلك بهدف تحسين األداء ال غير)‪ .‬وضعنا حلقة ‪ً while‬‬
‫ّ‬
‫الطالب الذين يرغب المستخدم بإدخال بياناتهم‪ .‬الحظ‬ ‫القديمة وذلك ألنّنا ال نعرف على وجه التحديد عدد‬
‫ي‪.‬‬
‫شرط استمرار الحلقة ‪continueCondition‬الذي يحمل القيمة ‪true‬بشكل افتراض ّ‬

‫أصبح البرنامج غير مقيّ ٍّد بعدد محدّد من الطالب‪ ،‬فبعد إدخال بيانات كل طالب‪ ،‬سيعرض البرنامج رسالة‬
‫يخيّر فيها المستخدم في إضافة المزيد أم التوقّف فإذا اختار المستخدم التوقّف بإدخاله النص "‪ "N‬أو "‪"n‬‬
‫عندها سيسند البرنامج القيمة ‪ false‬للمتغيّر ‪continueCondition‬مما يؤدّي إلى الخروج‬
‫صرحنا عنه في‬
‫ّ‬ ‫من حلقة ‪while‬عند بدء الدورة التالية‪ .‬تنحصر وظيفة المتغيّر ‪counter‬الذي‬
‫إظهار ترتيب الطالب الحالي على الشاشة‪.‬‬

‫ّ‬
‫المخزنة ضمنها‬ ‫نستخدم الخاصيّة ‪Count‬للمجموعة ‪listStudents‬لمعرفة عدد العناصر الفعليّة‬
‫(تذ ّكر الخاصيّة ‪Length‬المماثلة لها في المصفوفات‪).‬‬

‫بعد تنفيذ البرنامج وإدخال بيانات ستة ّ‬


‫طالب‪ ،‬ستحصل على شكل شبيه بما يلي‪:‬‬

‫‪5‬‬ ‫م‪.‬بسمة سراقبي‬


‫جامعة ادلب‬
‫كلية الهندسة المعلوماتية‬
‫السنة الثانية‪ -‬مادة برمجة متقدمة ‪1‬‬

‫نمرر لهذا‬
‫يوجد تابع اسمه ‪RemoveAt‬ضمن هذه المجموعة يسمح بإزالة عنصر من القائمة‪ ،‬حيث ّ‬
‫األول هو ‪ )0‬ليعمل هذا التابع على إزالته وإعادة‬ ‫التابع دليل ‪ index‬العنصر المراد إزالته (دليل العنصر ّ‬
‫تعيين أدلّة جميع العناصر بعد إزالة العنصر المطلوب‪ .‬انظر الشيفرة التالية‪:‬‬

‫;)"‪listStrings.Add("Bird‬‬
‫;)"‪listStrings.Add("Fish‬‬
‫;)"‪listStrings.Add("Frog‬‬

‫;)‪listStrings.RemoveAt(1‬‬

‫أنشأنا في الشيفرة السابقة مجموعة من النوع ( >‪List<string‬عناصرها من النوع ‪،string‬‬

‫‪6‬‬ ‫م‪.‬بسمة سراقبي‬


‫جامعة ادلب‬
‫كلية الهندسة المعلوماتية‬
‫السنة الثانية‪ -‬مادة برمجة متقدمة ‪1‬‬
‫ث ّم أضفنا إليها ثالثة عناصر‪ .‬يؤدّي استدعاء التابع )‪ RemoveAt(1‬إلى إزالة العنصر ذو الدليل ‪1‬‬
‫من هذه المجموعة‪ ،‬أي ّ‬
‫أن العنصر ذو القيمة ‪ Fish‬سيُزال من هذه القائمة‪.‬‬

‫يوجد تابع مشابه لهذا التابع اسمه ‪ Remove‬يتطلّب أن ّ‬


‫تمرر إليه مرج ًعا لكائن موجود في هذه المجموعة‬
‫لهذه المجموعة عبارة عن نوع قيمة‬ ‫لتتم إزالته‪ .‬فإذا كان النوع العمومي‬
‫فعندها يكفي تمرير القيمة المراد إزالتها‬ ‫مثل >‪List<int‬أو >‪List<double‬‬
‫للتابع ‪Remove‬فحسب‪ .‬عل ًما ّ‬
‫أن هذا التابع يزيل ّأول نتيجة تطابق يصادفها في هذه المجموعة‪.‬‬

‫ضا التابع ‪Reverse‬الذي يعمل على عكس ترتيب العناصر الموجودة في المجموعة‪ ،‬حيث‬
‫يوجد أي ً‬
‫األول‪ .‬كما يوجد التابع ‪Sort‬الذي يعمل على‬
‫األول هو األخير‪ ،‬والعنصر األخير هو ّ‬
‫يصبح العنصر ّ‬
‫ي‬
‫ترتيب العناصر ضمن المجموعة وفق الترتيب االفتراضي (بالنسبة لألنواع المض ّمنة) أو وفق ترتيب كيف ّ‬
‫يمكن للمبرمج أن يختاره‪.‬‬

‫وهناك تابع مفيد آخر وهو ‪BinarySearch‬الذي يجري خوارزمية البحث الشهيرة على عناصر‬
‫نمرر إليه القيمة المراد البحث عنها (أو مرجع الكائن الذي نريد البحث عنه) ويُرجع هذا‬
‫المجموعة‪ ،‬حيث ّ‬
‫أن هذا الدليل يمثّل دليل العنصر ضمن‬
‫التابع دليل العنصر ضمن المجموعة في حال وجده‪ .‬مع االنتباه إلى ّ‬
‫ي قبل أن يجري عملية البحث‪ .‬إذا أردت‬ ‫المجموعة على اعتبارها مرتّبة‪ .‬إذ أنّه يقوم بترتيبها بشكل داخل ّ‬
‫الحصول على نتائج منطقيّة‪ ،‬فاعمل على ترتيب مجموعتك باستخدام التابع ‪Sort‬قبل‬
‫استدعاء ‪BinarySearch.‬‬

‫يمكننا الوصول إلى عنصر محدّد ضمن مجموعة عموميّة بنفس األسلوب التي تحدّثنا عنه في المجموعات‬
‫العاديّة‪ ،‬مع مالحظة أ ّننا لن نحتاج إلى عامل التحويل بين األنواع‪ ،‬وبالتالي التخ ّلص من عمليت ّ‬
‫ي التعليب‬
‫ضا من التابع ‪Insert‬لإلدراج ضمن موقع‬
‫‪boxing‬وإلغاء التعليب ‪ unboxing.‬كما يمكن االستفادة أي ً‬
‫ضا في المجموعات العاديّة‪.‬‬
‫ُمحدّد‪ ،‬والذي تحدّثنا عنه أي ً‬

‫توجد توابع أخرى مفيدة ضمن المجموعة ‪<List<T‬ولكنّنا لن نستطيع الخوض فيها قبل أن نتحدّث عن‬
‫النواب ‪ delegates‬في درس الحق‪.‬‬
‫ّ‬

‫مالحظة ‪:‬توجد طريقة سريعة وفعّالة إلنشاء مجموعة >‪List<T‬وإسناد عناصر إليها مباشرة ً في حال‬
‫كان عدد العناصر محدّد ومعروف سل ًفا‪ .‬فإذا أردنا إنشاء مجموعة من النوع >‪List<int‬تحوي‬
‫العناصر ‪ 10 ،5 ،2 ،1‬يمكنك كتابة العبارة التالية لهذا الغرض‪:‬‬

‫;} ‪List<int> listNumbers = new List<int>() { 10, 5, 2, 1‬‬

‫‪7‬‬ ‫م‪.‬بسمة سراقبي‬


‫جامعة ادلب‬
‫كلية الهندسة المعلوماتية‬
‫السنة الثانية‪ -‬مادة برمجة متقدمة ‪1‬‬
‫تنشئ هذه العبارة مجموعة من النوع >‪List<int‬وتضيف إليها العناصر ‪ 10‬و‪ 5‬و‪ 2‬و‪ 1‬ث ّم تسند هذه‬
‫المجموعة إلى المتغيّر ‪listNumbers.‬‬

‫تمارين داعمة‬
‫تمرين ‪1‬‬

‫ويخزنها ضمن مجموعة من‬ ‫ّ‬ ‫اكتب برنام ًجا يطلب من المستخدم إدخال خمس قيم نصيّة‪،‬‬
‫النوع ‪<List<string.‬ث ّم استخدم التابع ‪Reverse‬لعكس ترتيب العناصر ضمن هذه المجموعة‪،‬‬
‫ث ّم اطبع النتائج على الشاشة‪.‬‬

‫تمرين ‪2‬‬

‫اكتب برنام ًجا يطلب من المستخدم إدخال قيم عدديّة من النوع ‪double‬بقدر ما يريد‪ ،‬وبعد أن يفرغ من‬
‫اإلدخال‪ ،‬احسب المتوسّط الحسابي (المعدّل) لهذه األعداد‪ ،‬ورتّبها باستخدام التابع ‪ ،Sort‬ثم اطبعها على‬
‫الشاشة‪ ،‬مع المتوسّط الحسابي لها‪.‬‬

‫الخالصة‬

‫ي‬
‫تعرفنا في هذا الدرس على الواجهات ‪ Interfaces‬والمجموعات ‪ Collections.‬من النادر أن يخلو أ ّ‬ ‫ّ‬
‫ي من استخدام المجموعات أو الواجهات‪ ،‬وفي الحقيقة هناك العديد من بنى المجموعات المفيدة‬
‫برنامج فعل ّ‬
‫والرائعة للمجموعات في سلسلة قادمة‪.‬‬
‫التي لم نتناولها في هذا الدرس‪ .‬سنحاول أن نتوسّع في المزايا القويّة ّ‬

‫‪8‬‬ ‫م‪.‬بسمة سراقبي‬

You might also like