التكرار المحدَّد
أهداف التعلّم
بعد هذا القسم
- ستعرف الفرق بين التكرار المحدَّد والتكرار غير المحدَّد
- ستعرف كيف تعمل حلقة
forفي Python- ستكون قادرًا على استخدام حلقة
forللتكرار على القوائم والسلاسل النصية
يمكنك استخدام حلقة while للمرور على عناصر قائمة، تمامًا كما استخدمنا حلقات while للمرور على السلاسل النصية. ويطبع البرنامج التالي عناصر القائمة، كل عنصر في سطر منفصل:
my_list = [3, 2, 4, 5, 2]
index = 0
while index < len(my_list):
print(my_list[index])
index += 1
3
2
4
5
2
هذا يعمل بطبيعة الحال، لكنه طريقة معقّدة بعض الشيء للمرور على قائمة، إذ عليك استخدام متغيّر مساعد index لتتذكّر العنصر الذي وصلت إليه في القائمة. ولحسن الحظ، توفّر Python طريقة أكثر حدسية للمرور على القوائم والسلاسل النصية والهياكل المشابهة الأخرى.
حلقة for
حين تريد المرور على مجموعة جاهزة من العناصر، تتكفّل بك حلقة for في Python بذلك. فمثلًا يمكن للحلقة أن تمرّ على جميع عناصر قائمة من الأول إلى الأخير.
عند استخدام حلقة while لا «يعرف» البرنامج مسبقًا كم تكرارًا ستؤديه الحلقة. فهي تتكرر حتى يصبح الشرط خاطئًا، أو حتى يتم الخروج من الحلقة بطريقة أخرى. ولهذا فإنها تندرج تحت التكرار غير المحدَّد. أما مع حلقة for فيُحدَّد عدد التكرارات عند إعداد الحلقة، ولهذا فإنها تندرج تحت التكرار المحدَّد.
والفكرة أن حلقة for تأخذ عناصر المجموعة واحدًا تلو الآخر، وتنفّذ الإجراءات نفسها على كل عنصر. فلا يحتاج المبرمج إلى التفكير في أي عنصر يجري معالجته في كل مرة. وصيغة حلقة for هي كما يلي:
for <variable> in <collection>:
<block>
تأخذ حلقة for عنصرًا من المجموعة، وتُسنده إلى المتغيّر، وتنفّذ كتلة الشيفرة، ثم تنتقل إلى العنصر التالي. وبعد أن تتم معالجة جميع عناصر المجموعة، يستمر تنفيذ البرنامج من السطر التالي للحلقة.

يطبع البرنامج التالي جميع عناصر قائمة باستخدام حلقة for:
my_list = [3, 2, 4, 5, 2]
for item in my_list:
print(item)
3
2
4
5
2
بالمقارنة مع المثال في بداية هذا القسم، يصبح الهيكل أسهل في الفهم بكثير. فحلقة for تجعل المرور المباشر على مجموعة عناصر أمرًا بسيطًا جدًا.
المبدأ نفسه ينطبق على محارف السلسلة النصية:
name = input("Please type in your name: ")
for character in name:
print(character)
Please type in your name: **Grace**
G
r
a
c
e
تمرين برمجي: مرصّع بالنجوم
اكتب برنامجًا يطلب من المستخدم كتابة سلسلة نصية. ثم يطبع البرنامج كل محرف من المُدخَل في سطر منفصل. وبعد كل محرف ينبغي أن تُطبع نجمة (*) في سطر خاص بها.
وهكذا ينبغي أن يعمل:
Please type in a string: **Python**
P
*
y
*
t
*
h
*
o
*
n
*
ملاحظة: هذا التمرين لا يطلب منك كتابة أي دوال، لذا يجب أن لا تضع أي شيفرة داخل كتلة if __name__ == "__main__".
الدالة range
كثيرًا ما تعرف عدد المرات التي تريد تكرار جزء معيّن من الشيفرة. فقد ترغب مثلًا في المرور على جميع الأعداد بين 1 و100. وتقوم الدالة range الموصولة بحلقة for بذلك نيابةً عنك.
هناك بضع طرق مختلفة لاستدعاء دالة range. وأبسطها هي إعطاء الدالة وسيطًا واحدًا فقط، يدلّ على نقطة نهاية المدى. أما نقطة النهاية نفسها فمستثناة، تمامًا كما في تقطيع السلاسل النصية. وبعبارة أخرى، يوفّر الاستدعاء range(n) حلقة بمدى من 0 إلى n-1:
for i in range(5):
print(i)
0
1
2
3
4
مع وسيطين، تُرجع الدالة مدى بين العددَين. وتوفّر الدالة range(a,b) مدى يبدأ من a وينتهي عند b-1:
for i in range(3, 7):
print(i)
3
4
5
6
وأخيرًا، بوسيط ثالث يمكنك أيضًا تحديد حجم الخطوة التي يتخذها المدى بين كل قيمة. ويوفّر الاستدعاء range(a, b, c) مدى يبدأ من a وينتهي عند b-1 ويتغيّر بمقدار c في كل خطوة:
for i in range(1, 9, 2):
print(i)
1
3
5
7
ويمكن أن تكون الخطوة سالبة. عندئذٍ يكون المدى بترتيب معكوس. ولاحظ أن الوسيطَين الأوّليَين معكوكان هنا أيضًا:
for i in range(6, 2, -1):
print(i)
6
5
4
3
تمرين برمجي: من السالب إلى الموجب
اكتب برنامجًا يطلب من المستخدم عددًا صحيحًا موجبًا N. ثم يطبع البرنامج جميع الأعداد بين -N وN شاملًا الطرفين، لكن مع استثناء العدد 0. وينبغي أن يُطبع كل عدد في سطر منفصل.
مثال على السلوك المتوقع:
Please type in a positive integer: **4**
-4
-3
-2
-1
1
2
3
4
ملاحظة: هذا التمرين لا يطلب منك كتابة أي دوال، لذا يجب أن لا تضع أي شيفرة داخل كتلة if __name__ == "__main__".
من مدى إلى قائمة
تُرجع الدالة range كائنَ مدى، يتصرّف في جوانب كثيرة كأنه قائمة، لكنه ليس قائمة في الواقع. فإذا حاولت طباعة القيمة التي تُرجعها الدالة، فلن ترى سوى وصف لكائن المدى:
numbers = range(2, 7)
print(numbers)
range(2, 7)
تحوّل الدالة list المدى إلى قائمة. وستحتوي القائمة على جميع القيم الموجودة في المدى. أما دورة البرمجة المتقدمة، التي تأتي بعد هذه الدورة، فستُلقي مزيدًا من الضوء على هذا الموضوع.
numbers = list(range(2, 7))
print(numbers)
[2, 3, 4, 5, 6]
تذكير بمتطلّبات الاختبارات الآلية
حتى الآن، حين كان يُطلب منك في التمارين كتابة دوال، كانت القوالب تبدو هكذا:
# Write your solution here
# You can test your function by calling it within the following block
if __name__ == "__main__":
sentence = "it was a dark and stormy python"
print(first_word(sentence))
print(second_word(sentence))
print(last_word(sentence))
من الآن فصاعدًا لن تتكرر التذكيرات في القوالب باستخدام كتلة if __name__ == "__main__". لكن الاختبارات الآلية ستظل تتطلّب استخدامها، لذا عليك إضافة الكتلة بنفسك حين تختبر دالتك داخل الدالة الرئيسية لبرنامجك.
ملاحظة: بعض التمارين، مثل تمرين المتناظرات (palindromes) الذي سيأتي لاحقًا في هذا القسم، تتطلّب منك أيضًا كتابة شيفرة تستدعي الدالة التي كتبتها. ولا ينبغي أن توضع هذه الشيفرة داخل كتلة if __name__ == "__main__". ولن تنفّذ الاختبارات الآلية أي شيفرة داخل تلك الكتلة، لذا لن يكون حلّك مكتملًا إن وضعت استدعاءات دوالك هناك.
تمرين برمجي: قائمة نجوم
اكتب دالة اسمها
list_of_stars، تأخذ قائمة من الأعداد الصحيحة كوسيط لها. وينبغي أن تطبع الدالة أسطرًا من محارف النجمة. وتحدّد الأعداد في القائمة عدد النجوم التي ينبغي أن يحتوي عليها كل سطر.
فمثلًا، مع استدعاء الدالة list_of_stars([3, 7, 1, 1, 2]) ينبغي أن يُطبع ما يلي:
***
*******
*
*
**
تمرين برمجي: الأناغرام
اكتب دالة اسمها
anagrams، تأخذ سلسلتين نصيتين كوسيطين. وتُرجع الدالةTrueإذا كانت السلسلتان النصيتان تباديل حرفية (anagrams) لإحداهما الأخرى. وتعدّ كلمتان تباديل حرفية لإحداهما الأخرى إذا احتوتا على المحارف نفسها تمامًا.
وبعض الأمثلة على كيفية عمل الدالة:
print(anagrams("tame", "meta")) # True
print(anagrams("tame", "mate")) # True
print(anagrams("tame", "team")) # True
print(anagrams("tabby", "batty")) # False
print(anagrams("python", "java")) # False
تلميح: يمكن استخدام الدالة sorted على السلاسل النصية أيضًا.
تمرين برمجي: المتناظرات
اكتب دالة اسمها
palindromes، تأخذ وسيطًا من نوع سلسلة نصية وتُرجعTrueإذا كانت السلسلة النصية متناظرة (palindrome). والمتناظرات كلمات تُكتب بنفس الطريقة تمامًا إلى الأمام وإلى الخلف.
يُرجى أيضًا كتابة برنامج رئيسي يطلب من المستخدم كتابة كلمات حتى يكتب كلمة متناظرة:
Please type in a palindrome: **python**
that wasn't a palindrome
Please type in a palindrome: **java**
that wasn't a palindrome
Please type in a palindrome: **oddoreven**
that wasn't a palindrome
Please type in a palindrome: **neveroddoreven**
neveroddoreven is a palindrome!
ملاحظة: يجب ألا يكون البرنامج الرئيسي داخل كتلة if __name__ == "__main__":
تمرين برمجي: مجموع الأعداد الموجبة
اكتب دالة اسمها
sum_of_positives، تأخذ قائمة من الأعداد الصحيحة كوسيط لها. وتُرجع الدالة مجموع القيم الموجبة في القائمة.
my_list = [1, -2, 3, -4, 5]
result = sum_of_positives(my_list)
print("The result is", result)
The result is 9
في هذه التمارين سنستخدم القوائم كوسائط وقيم إعادَة. وقد تناول ذلك القسم السابق، إن احتجت إلى مراجعة.
تمرين برمجي: الأعداد الزوجية
اكتب دالة اسمها
even_numbers، تأخذ قائمة من الأعداد الصحيحة كوسيط. وتُرجع الدالة قائمة جديدة تحتوي على الأعداد الزوجية من القائمة الأصلية.
my_list = [1, 2, 3, 4, 5]
new_list = even_numbers(my_list)
print("original", my_list)
print("new", new_list)
original [1, 2, 3, 4, 5]
new [2, 4]
تمرين برمجي: مجموع القوائم
اكتب دالة اسمها
list_sumتأخذ قائمتين من الأعداد الصحيحة كوسيطين. وتُرجع الدالة قائمة جديدة تحتوي على مجاميع العناصر عند كل فهرس في القائمتين الأصليتين. ويمكنك أن تفترض أن للقائمتين العدد نفسه من العناصر.
مثال على عمل الدالة:
a = [1, 2, 3]
b = [7, 8, 9]
print(list_sum(a, b)) # [8, 10, 12]
تمرين برمجي: الأعداد المختلفة
اكتب دالة اسمها
distinct_numbers، تأخذ قائمة من الأعداد الصحيحة كوسيط لها. وتُرجع الدالة قائمة جديدة تحتوي على أعداد القائمة الأصلية مرتَّبة حسب القيمة، بحيث لا يظهر كل عدد مميَّز إلا مرة واحدة فقط.
my_list = [3, 2, 2, 1, 3, 3, 1]
print(distinct_numbers(my_list)) # [1, 2, 3]
إيجاد أفضل عنصر أو أسوأ عنصر في قائمة
من المهام البرمجية الشائعة جدًا إيجاد أفضل عنصر أو أسوأ عنصر في قائمة وفق معايير ما. والحل البسيط هو استخدام متغيّر مساعد «يتذكّر» أيّ العناصر التي عولجت حتى الآن هو الأنسب. ثم يُقارَن هذا الاختيار المؤقّت الأفضل بكل عنصر على حدة، وفي نهاية التكرار يحتوي المتغيّر على الأفضل من بين العناصر كلها.
مسوّدة تقريبية لا تعمل كما ينبغي بعد:
best = initial_value # The initial value depends on the situation
for item in my_list:
if item is better than best:
best = item
# We now have the best one figured out!
تعتمد تفاصيل شيفرة البرنامج النهائية على نوع العناصر الموجودة في القائمة، وكذلك على معايير اختيار أفضل عنصر (أو أسوأه). وقد تحتاج أحيانًا إلى أكثر من متغيّر مساعد.
لنتمرّن قليلًا على هذه الطريقة.
تمرين برمجي: طول الأطول في القائمة
اكتب دالة اسمها
length_of_longest، تأخذ قائمة من السلاسل النصية كوسيط لها. وتُرجع الدالة طول أطول سلسلة نصية.
my_list = ["first", "second", "fourth", "eleventh"]
result = length_of_longest(my_list)
print(result)
my_list = ["adele", "mark", "dorothy", "tim", "hedy", "richard"]
result = length_of_longest(my_list)
print(result)
8
7
تمرين برمجي: الأقصر في القائمة
اكتب دالة اسمها
shortest، تأخذ قائمة من السلاسل النصية كوسيط لها. وتُرجع الدالة أيّ السلاسل النصية كانت الأقصر. وإذا كان هناك أكثر من سلسلة متساوية في القصر، فيمكن للدالة أن تُرجع أيّ من تلك السلاسل الأقصر (ولن تحدث هذه الحالة في الاختبارات). ويمكنك أن تفترض أنه لا توجد سلاسل نصية فارغة في القائمة.
my_list = ["first", "second", "fourth", "eleventh"]
result = shortest(my_list)
print(result)
my_list = ["adele", "mark", "dorothy", "tim", "hedy", "richard"]
result = shortest(my_list)
print(result)
first
tim
تمرين برمجي: كل الأطول في القائمة
اكتب دالة اسمها
all_the_longest، تأخذ قائمة من السلاسل النصية كوسيط لها. وينبغي أن تُرجع الدالة قائمة جديدة تحتوي على أطول سلسلة نصية في القائمة الأصلية. وإذا كان هناك أكثر من سلسلة متساوية في الطول، فينبغي أن تُرجع الدالة جميع تلك السلاسل الأطول.
وينبغي أن يكون ترتيب السلاسل النصية في القائمة المُرجَعة هو نفسه الترتيب في القائمة الأصلية.
my_list = ["first", "second", "fourth", "eleventh"]
result = all_the_longest(my_list)
print(result) # ['eleventh']
my_list = ["adele", "mark", "dorothy", "tim", "hedy", "richard"]
result = all_the_longest(my_list)
print(result) # ['dorothy', 'richard']