تعد عملية التكرار عبر القوائم واحدة من أكثر المهارات الأساسية في بايثون. في بعض المواقف، قد تجد نفسك مضطرًا إلى تكرار قوائم متعددة جنبًا إلى جنب، وأخذ عنصر واحد من كل قائمة وإجراء عملية به. إذا كنت جديدًا على بايثون، فليس من الواضح دائمًا كيفية القيام بذلك أو التحذيرات وأفضل الممارسات الموجودة لهذه المهمة.
في هذه المقالة، سنتعلم أفضل طريقة للتكرار عبر قوائم متعددة في بايثون. سنبدأ بحلقة for بسيطة، ونتعلم كيفية التكرار عبر قوائم متعددة “يدويًا”، ثم نستكشف فائدة الدالتين zip وzip_longest. يجب أن تكون على دراية بالتسلسلات مثل الثنائيات والقوائم وأن يكون لديك فهم أساسي لكيفية عمل التكرار.
تكرار القوائم في بايثون
دعنا نلخص كيفية تكرار قائمة في بايثون. الطريقة الأبسط هي استخدام حلقة for لتكرار كل عنصر من عناصر القائمة. إليك مثال:
animals = ["cat", "dog", "monkey"]
for animal in animals:
print(animal)
# output:
# cat
# dog
# monkey
تمر حلقة for
على كل حيوان في قائمة animals
، وتضعه في متغير يسمى animal
، ثم تطبعه.
هناك إمكانية أخرى تتمثل في الوصول المباشر إلى كل عنصر في القائمة باستخدام فهرسه. وعادةً ما يتضمن هذا إنشاء نطاق من الأرقام يصل إلى طول القائمة (المتغير n في المثال أدناه)، ثم تكرار ذلك النطاق، ثم استخدام كل رقم كفهرس لكل عنصر في القائمة.
هكذا يبدو الأمر:
animals = ["cat", "dog", "monkey"]
n = len(animals)
for i in range(n):
animal = animals[i]
print(animal)
# output:
# cat
# dog
# monkey
على الرغم من الاختلافات في بناء الجملة، فإن هذه التكرارات تعطي نفس النتيجة تمامًا كما كانت من قبل. نظرًا لأنها أكثر تعقيدًا بعض الشيء، فإن حلقة for animal in animals
هي المفضلة بشكل عام عندما يكون كل ما تحتاجه هو التكرار على قائمة واحدة.
التكرار اليدوي على قوائم متعددة في بايثون
حتى الآن، تعتبر حلقات for سهلة بدرجة كافية. ولكن ماذا يحدث إذا كان لدينا قوائم متعددة لتكرارها؟
تظهر هذه المشكلة عندما يكون لدينا بيانات ذات صلة ولكنها مخزنة في قوائم مختلفة. على سبيل المثال، ضع في اعتبارك القائمتين أدناه، students
و grades
:
students = ["John", "Mary", "Luke"]
grades = [9.0, 8.5, 7.5]
على الرغم من أنهما قائمتان منفصلتان، إلا أنهما مرتبطتان بالمؤشر: حصل John (العنصر الأول في قائمة students
) على درجة 9.0
(العنصر الأول في قائمة grades
)، وحصلت ماري على 8.5
، وهكذا. كيف يمكننا تكرار القائمتين وطباعة كل طالب إلى جانب درجته الخاصة؟
أحد الحلول هو استخدام التكرار القائم على الفهرس الذي استخدمناه من قبل. إذا استخدمنا نفس الفهرس لأخذ عنصر من كل قائمة، فسنحصل في النهاية على زوج القيم المناسب. وهذا هو الشكل الذي يبدو عليه الأمر:
students = ["John", "Mary", "Luke"]
grades = [9.0, 8.5, 7.5]
n = len(students)
for i in range(n):
student = students[i]
grade = grades[i]
print(student, "got a grade of", grade)
# output:
# John got a grade of 9.0
# Mary got a grade of 8.5
# Luke got a grade of 7.5
كما ترى، يتم طباعة كل طالب إلى جانب درجاته. لاحظ أيضًا كيف أن القائمة المستخدمة عند حساب n لا تهم حقًا. كان من الممكن أن تعمل بنفس الطريقة إذا كتبنا n = len(grades)
بدلاً من ذلك.
المشكلة في استخدام المؤشرات
لكن مهلا – هناك مشكلة! ماذا يحدث إذا لم يكن حجم قائمة students
وgrades
متماثلًا؟ في هذه الحالة، تحدث أشياء مختلفة، اعتمادًا على ما إذا كنت تستخدم القائمة الأقصر أو الأطول لتوليد الفهارس.
إذا تم توفير القائمة الأقصر، فستنتهي الحلقة قبل الوصول إلى العناصر الإضافية للقائمة الأطول. في المثال أدناه، لاحظ كيف لا يتم الوصول إلى الدرجة الأخيرة على الإطلاق:
students = ["John", "Mary"]
grades = [9.0, 8.5, 7.5]
n = len(students)
for i in range(n):
student = students[i]
grade = grades[i]
print(student, "got a grade of", grade)
# output:
# John got a grade of 9.0
# Mary got a grade of 8.5
من ناحية أخرى، إذا تم استخدام القائمة الأطول لحساب n، فسوف يصطدم الكود في النهاية بـ IndexError
عند محاولة أخذ عنصر من القائمة الأقصر:
students = ["John", "Mary", "Luke", "Anna"]
grades = [9.0, 8.5, 7.5]
n = len(students)
for i in range(n):
student = students[i]
grade = grades[i]
print(student, "got a grade of", grade)
# output:
# John got a grade of 9.0
# Mary got a grade of 8.5
# Luke got a grade of 7.5
# IndexError: list index out of range
عندما يكون i
هو 3، students[i]
يصبح students[3]
ويعيد العنصر “Anna
“. ومع ذلك، في نفس التكرار، لا يوجد عنصر لـ grades[3]
. يؤدي هذا إلى IndexError
الموضح أعلاه.
استخدام دالة zip للتكرار التلقائي على قوائم متعددة
هناك بديل أبسط كثيرًا لتكرار القوائم المتعددة في بايثون: دالة zip. وهي دالة مدمجة تتيح لك تكرار قائمتين أو أكثر جنبًا إلى جنب.
قارن المثال أدناه مع الكود السابق لدينا ولاحظ مدى بساطة وجمال مظهره:
students = ["John", "Mary", "Luke"]
grades = [9.0, 8.5, 7.5]
for student, grade in zip(students, grades):
print(student, "got a grade of", grade)
# output:
# John got a grade of 9.0
# Mary got a grade of 8.5
# Luke got a grade of 7.5
باستخدام دالة zip
، لا نحتاج إلى القلق بشأن تخزين طول القائمة في متغير مثل n
أو الحصول يدويًا على العناصر باستخدام الفهرس i
. ببساطة، نضع القوائم التي نريد تكرارها في دالة zip
ونترك لبايثون الاهتمام بالتفاصيل. لاحظ أيضًا كيف تشير المتغيرات student
وgrade
إلى عناصر داخل كل قائمة تم تمريرها إلى دالة zip
بنفس الترتيب.
يمكنك أيضًا استخدام دالة zip
في بايثون لتكرار أكثر من قائمتين جنبًا إلى جنب. ما عليك سوى وضعها جميعًا في دالة zip
، ثم استخدام نفس عدد المتغيرات في حلقة for
لتخزين العناصر الخاصة بكل قائمة:
students = ["John", "Mary", "Luke"]
ages = [12, 10, 13]
grades = [9.0, 8.5, 7.5]
for student, age, grade in zip(students, ages, grades):
print(student, "is", age, "years old and got a grade of", grade)
# output:
# John is 12 years old and got a grade of 9.0
# Mary is 10 years old and got a grade of 8.5
# Luke is 13 years old and got a grade of 7.5
استخدام دالة zip_longest للوصول إلى جميع العناصر في قوائم متعددة في بايثون
ماذا عن القوائم التي تحتوي على عدد مختلف من العناصر في كل منها؟ حسنًا، سلوك دالة zip
هو ببساطة التوقف عن التكرار بمجرد زيارة جميع العناصر في أقصر قائمة. على سبيل المثال، يتم تنفيذ الحلقة أدناه مرة واحدة فقط لأن القائمة students تحتوي على إدخال واحد فقط:
students = ["John"]
ages = [12, 10, 13]
grades = [9.0, 8.5, 7.5]
for student, age, grade in zip(students, ages, grades):
print(student, "is", age, "years old and got a grade of", grade)
# output:
# John is 12 years old and got a grade of 9.0
إذا كنت تريد زيارة جميع العناصر في جميع القوائم، فيمكنك استخدام دالة zip_longest
بدلاً من ذلك. توجد هذه الدالة في وحدة itertools
التي تأتي مع مكتبة بايثون القياسية، لذا نحتاج فقط إلى استيرادها لاستخدامها.
كما يوحي الاسم، تعمل دالة zip_longest
بشكل مشابه جدًا لدالة zip
العادية، لكنها تصل إلى جميع العناصر – حتى تلك الموجودة في القوائم الأطول. للقيام بذلك، تقوم بملء القيم في القوائم الأقصر بقيمة افتراضية. إليك كيف تبدو في العمل:
from itertools import zip_longest
students = ["John", "Mary", "Luke"]
ages = [12, 10]
grades = [9.0]
for student, age, grade in zip_longest(students, ages, grades, fillvalue="??"):
print(student, "is", age, "years old and got a grade of", grade)
# output:
# John is 12 years old and got a grade of 9.0
# Mary is 10 years old and got a grade of ??
# Luke is ?? years old and got a grade of ??
كما ترى، على الرغم من أن قوائم الأعمار والدرجات أقصر من قوائم الطلاب، فقد كررنا جميع عناصر الطلاب. ولجعل ذلك ممكنًا، يتم تعبئة القوائم الأقصر بقيمة تعبئة أثناء الحلقة. بشكل افتراضي، يتم استخدام قيمة None كقيمة تعبئة، ولكن هنا استخدمنا السلسلة “??
” لتنسيق أفضل. مفيد جدًا!
اختتام حلقات بايثون وzip وzip_longest
كما رأينا، تساعد دالتا zip
وzip_longest
حقًا عندما تحتاج إلى تكرار قوائم متعددة في بايثون. باستخدام هذه الدالات، لا داعي للقلق بشأن الفهارس وأحجام القوائم ويمكنك التركيز على عملية التكرار نفسها. تذكر: استخدم zip
عندما تريد إيقاف حلقتك بعد استنفاد أقصر قائمة؛ استخدم zip_longest
إذا كنت تريد الوصول إلى كل عنصر في القائمة الأطول.
الآن يجب أن تكون مستعدًا لتكرار قوائم بايثون المتعددة، بغض النظر عن عددها أو طولها.
اكتشاف المزيد من بايثون العربي
اشترك للحصول على أحدث التدوينات المرسلة إلى بريدك الإلكتروني.