تخطَّ إلى المحتوى

List Comprehension في Python: بناء القوائم في سطر واحد

الدرس 21 من 25 · Python

كثيراً ما تحتاج أن تبني قائمة جديدة من قائمة موجودة: مربعات الأرقام، أو الأسماء بحروف كبيرة، أو الدرجات الناجحة فقط. تعلمت أن تفعل ذلك بحلقة for و append. في هذا الدرس ستتعلم طريقة أقصر وأجمل يحبها مبرمجو Python: List Comprehension، أي بناء القائمة بصيغة مختصرة.

لنفترض أننا نريد قائمة بمربعات الأرقام. هذه الطريقة التي تعرفها:

numbers = [1, 2, 3, 4, 5]
squares = []
for n in numbers:
squares.append(n * n)
print(squares)
الناتج
[1, 4, 9, 16, 25]

ثلاثة أسطر لفكرة بسيطة. والآن الفكرة نفسها بالصيغة المختصرة:

squares = [n * n for n in numbers]
print(squares)
الناتج
[1, 4, 9, 16, 25]

اقرأها كأنها جملة عادية: «ضع n * n لكل n في numbers». الصيغة العامة هي:

[التعبير for العنصر in المصدر]
  • التعبير: ما تريد وضعه في القائمة الجديدة.
  • العنصر: اسم مؤقت لكل قيمة، مثل متغير الحلقة تماماً.
  • المصدر: قائمة، أو range، أو نص، أو أي شيء يمكن المرور عليه.

تخيّلها مثل خط إنتاج في مصنع: تدخل العناصر من جهة واحداً واحداً، تُجرى على كل عنصر العملية نفسها، وتخرج من الجهة الأخرى قائمة جديدة.

التعبير يمكن أن يكون أي شيء: عملية حسابية، أو استدعاء دالة، أو تابعاً من توابع النصوص:

names = ["sara", "omar", "laila"]
print([name.capitalize() for name in names])
print([len(name) for name in names])
print([n * 10 for n in range(1, 6)])
الناتج
['Sara', 'Omar', 'Laila']
[4, 4, 5]
[10, 20, 30, 40, 50]

لاحظ أن القائمة الأصلية names لم تتغير. الصيغة المختصرة تنشئ دائماً قائمة جديدة.

يمكنك إضافة شرط في آخر الصيغة، فلا يدخل القائمة الجديدة إلا العنصر الذي يحقق الشرط:

evens = [n for n in range(1, 11) if n % 2 == 0]
print(evens)
long_names = [name for name in names if len(name) > 4]
print(long_names)
الناتج
[2, 4, 6, 8, 10]
['laila']

اقرأها: «ضع n لكل n من 1 إلى 10 إذا كان n زوجياً». وتستطيع الجمع بين التحويل والتصفية معاً:

grades = [45, 80, 62, 30, 91]
bonus = [g + 5 for g in grades if g >= 50]
print(bonus)
الناتج
[85, 67, 96]

هنا اخترنا الدرجات الناجحة فقط، وأضفنا لكل واحدة خمس درجات.

الاختيار بين قيمتين: if و else

Section titled “الاختيار بين قيمتين: if و else”

ماذا لو أردت كل العناصر، لكن بقيمة مختلفة حسب الشرط؟ هنا نكتب if و else في أول الصيغة، داخل التعبير نفسه:

results = ["ناجح" if g >= 50 else "راسب" for g in grades]
print(results)
الناتج
['راسب', 'ناجح', 'ناجح', 'راسب', 'ناجح']

القواميس والمجموعات أيضاً

Section titled “القواميس والمجموعات أيضاً”

الفكرة نفسها تعمل مع القواميس والمجموعات، لكن بأقواس معقوفة:

prices = {"قلم": 5, "دفتر": 12, "حقيبة": 150}
doubled = {item: price * 2 for item, price in prices.items()}
print(doubled)
lengths = {len(word) for word in ["أحمد", "منى", "علي", "سارة"]}
print(lengths)
الناتج
{'قلم': 10, 'دفتر': 24, 'حقيبة': 300}
{3, 4}

في القاموس نكتب المفتاح: القيمة قبل for. وفي المجموعة حُذف التكرار تلقائياً كما تعلمت في درس المجموعات: أربعة أسماء، لكن طولين مختلفين فقط.

إذا كنت سترسل النتيجة مباشرة إلى دالة مثل sum أو max، فيمكنك حذف الأقواس المربعة:

print(sum(n * n for n in numbers))
print(max(len(name) for name in names))
الناتج
55
5

عندك قائمة درجات الحرارة بالمئوية: [0, 18, 25, 37, 100]. اكتب بالصيغة المختصرة:

  1. قائمة بالدرجات نفسها بالفهرنهايت (المعادلة: c * 9 / 5 + 32).
  2. قائمة بالدرجات الأعلى من 20 فقط.
  3. قائمة فيها «حار» إذا كانت الدرجة 30 أو أكثر، و«معتدل» لغير ذلك.
الناتج
[32.0, 64.4, 77.0, 98.6, 212.0]
[25, 37, 100]
['معتدل', 'معتدل', 'معتدل', 'حار', 'حار']
  • نسيان الأقواس المربعة: squares = (n * n for n in numbers) بأقواس عادية لا تنشئ قائمة، بل شيئاً اسمه «مولّد»، وعند طباعته ترى <generator object ...> بدلاً من الأرقام.
  • وضع else في الآخر: [n for n in numbers if n > 2 else 0] خطأ في الصياغة. if ... else تُكتب قبل for.
  • استخدامها لتنفيذ أوامر فقط: لا تكتب [print(n) for n in numbers]. إذا كنت لا تحتاج القائمة الناتجة، فالحلقة العادية هي الصحيحة.
  • الإفراط في التعقيد: سطر واحد لا يفهمه أحد ليس أفضل من أربعة أسطر واضحة.

سؤال

ما ناتج [n + 1 for n in [1, 2, 3]]؟

سؤال

ما ناتج [n for n in range(6) if n > 3]؟

  • الصيغة [تعبير for عنصر in مصدر] تبني قائمة جديدة في سطر واحد.
  • if في آخر الصيغة تصفّي العناصر، و if ... else في أولها تختار بين قيمتين.
  • الفكرة نفسها تعمل مع القواميس والمجموعات بأقواس معقوفة.
  • القائمة الأصلية لا تتغير، والنتيجة قائمة جديدة.
  • استخدمها عندما تجعل الكود أوضح، لا أعقد.