الدرس 8

القوائم (Lists)

الوحدة 3: هياكل البيانات وقت القراءة: 18 دقيقة

ما هي القوائم؟

القوائم هي مجموعات مرتبة وقابلة للتعديل يمكنها تخزين عناصر من أنواع مختلفة. إنها واحدة من أكثر هياكل البيانات تنوعاً واستخداماً في بايثون.

Python
# إنشاء القوائم
أرقام = [1, 2, 3, 4, 5]
فواكه = ["تفاح", "موز", "كرز"]
مختلطة = [1, "مرحباً", 3.14, True, None]
فارغة = []

# إنشاء قائمة من تسلسلات أخرى
حروف = list("بايثون")  # ['ب', 'ا', 'ي', 'ث', 'و', 'ن']
نطاق = list(range(5))   # [0, 1, 2, 3, 4]

print(f"الأرقام: {أرقام}")
print(f"الطول: {len(أرقام)}")  # 5

الفهرسة والوصول للعناصر

الوصول للعناصر باستخدام الفهرس (يبدأ من 0):

Python
فواكه = ["تفاح", "موز", "كرز", "تمر", "عنب"]

# الفهرسة الموجبة (من البداية)
print(فواكه[0])   # تفاح (الأول)
print(فواكه[1])   # موز (الثاني)
print(فواكه[4])   # عنب (الأخير)

# الفهرسة السالبة (من النهاية)
print(فواكه[-1])  # عنب (الأخير)
print(فواكه[-2])  # تمر (قبل الأخير)
print(فواكه[-5])  # تفاح (الأول)

# توضيح الفهارس:
#  +---+---+---+---+---+
#  | 0 | 1 | 2 | 3 | 4 |
#  +---+---+---+---+---+
#  |تفاح|موز|كرز|تمر|عنب|
#  +---+---+---+---+---+
#  |-5 |-4 |-3 |-2 |-1 |
#  +---+---+---+---+---+

تقطيع القوائم (Slicing)

استخراج أجزاء من القائمة باستخدام التقطيع:

Python
أرقام = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# الصياغة: القائمة[بداية:نهاية:خطوة]
# البداية تُشمل، النهاية لا تُشمل

print(أرقام[2:5])    # [2, 3, 4]
print(أرقام[:4])     # [0, 1, 2, 3] (من البداية)
print(أرقام[6:])     # [6, 7, 8, 9] (للنهاية)
print(أرقام[::2])    # [0, 2, 4, 6, 8] (كل ثاني)
print(أرقام[1::2])   # [1, 3, 5, 7, 9] (الفهارس الفردية)
print(أرقام[::-1])   # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] (معكوسة)

# التقطيع السالب
print(أرقام[-3:])    # [7, 8, 9] (آخر 3)
print(أرقام[:-3])    # [0, 1, 2, 3, 4, 5, 6] (كل شيء عدا آخر 3)
print(أرقام[-5:-2])  # [5, 6, 7]

# نسخ القائمة
نسخة = أرقام[:]
print(نسخة)  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

تعديل القوائم

القوائم قابلة للتعديل - يمكنك تغيير محتوياتها:

Python
فواكه = ["تفاح", "موز", "كرز"]

# تعديل عنصر واحد
فواكه[1] = "توت"
print(فواكه)  # ['تفاح', 'توت', 'كرز']

# تعديل شريحة
فواكه[1:3] = ["مانجو", "برتقال", "عنب"]
print(فواكه)  # ['تفاح', 'مانجو', 'برتقال', 'عنب']

# حذف عناصر
del فواكه[0]
print(فواكه)  # ['مانجو', 'برتقال', 'عنب']

# حذف شريحة
del فواكه[1:]
print(فواكه)  # ['مانجو']

# تفريغ القائمة
فواكه.clear()
print(فواكه)  # []

دوال القوائم

الدالة الوصف مثال
append(x) إضافة عنصر للنهاية قائمة.append(4)
extend(iter) إضافة عناصر متعددة قائمة.extend([4,5])
insert(i, x) إدراج في موضع قائمة.insert(0, 'أ')
remove(x) حذف أول تكرار قائمة.remove('أ')
pop([i]) حذف وإرجاع عنصر قائمة.pop()
index(x) إيجاد فهرس عنصر قائمة.index('أ')
count(x) عد التكرارات قائمة.count('أ')
sort() ترتيب في المكان قائمة.sort()
reverse() عكس في المكان قائمة.reverse()
copy() نسخة سطحية قائمة.copy()
Python
# إضافة عناصر
فواكه = ["تفاح"]
فواكه.append("موز")           # ['تفاح', 'موز']
فواكه.extend(["كرز", "تمر"])  # ['تفاح', 'موز', 'كرز', 'تمر']
فواكه.insert(1, "مشمش")       # ['تفاح', 'مشمش', 'موز', 'كرز', 'تمر']

# حذف عناصر
فواكه.remove("موز")       # حذف بالقيمة
محذوف = فواكه.pop()       # حذف وإرجاع الأخير
محذوف = فواكه.pop(0)      # حذف وإرجاع الأول

# إيجاد عناصر
ألوان = ["أحمر", "أخضر", "أزرق", "أخضر"]
print(ألوان.index("أخضر"))   # 1 (أول تكرار)
print(ألوان.count("أخضر"))   # 2

# الترتيب
أرقام = [3, 1, 4, 1, 5, 9, 2, 6]
أرقام.sort()                  # [1, 1, 2, 3, 4, 5, 6, 9]
أرقام.sort(reverse=True)      # [9, 6, 5, 4, 3, 2, 1, 1]

# sorted() ترجع قائمة جديدة (الأصلية لا تتغير)
أصلية = [3, 1, 4]
مرتبة_جديدة = sorted(أصلية)  # [1, 3, 4]
print(أصلية)                  # [3, 1, 4] (لم تتغير)

عمليات القوائم

Python
# الدمج
قائمة1 = [1, 2, 3]
قائمة2 = [4, 5, 6]
مدمجة = قائمة1 + قائمة2  # [1, 2, 3, 4, 5, 6]

# التكرار
مكررة = [0] * 5  # [0, 0, 0, 0, 0]
نمط = [1, 2] * 3  # [1, 2, 1, 2, 1, 2]

# فحص العضوية
فواكه = ["تفاح", "موز", "كرز"]
print("تفاح" in فواكه)       # True
print("عنب" in فواكه)        # False
print("عنب" not in فواكه)    # True

# الطول، الأدنى، الأقصى، المجموع
أرقام = [5, 2, 8, 1, 9]
print(len(أرقام))  # 5
print(min(أرقام))  # 1
print(max(أرقام))  # 9
print(sum(أرقام))  # 25

# المقارنة (عنصر بعنصر)
print([1, 2, 3] == [1, 2, 3])  # True
print([1, 2, 3] < [1, 2, 4])   # True

فهم القوائم (List Comprehensions)

طريقة موجزة لإنشاء القوائم:

Python
# الصياغة الأساسية: [تعبير for عنصر in تسلسل]

# مربعات الأرقام
مربعات = [س**2 for س in range(10)]
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

# مع شرط
مربعات_زوجية = [س**2 for س in range(10) if س % 2 == 0]
# [0, 4, 16, 36, 64]

# تحويل النصوص
كلمات = ["مرحباً", "عالم", "بايثون"]
أحرف_كبيرة = [كلمة.upper() for كلمة in كلمات]
# ['مرحباً', 'عالم', 'بايثون']

# حلقات متداخلة في الفهم
أزواج = [(س, ص) for س in range(3) for ص in range(3)]
# [(0,0), (0,1), (0,2), (1,0), (1,1), (1,2), (2,0), (2,1), (2,2)]

# تسطيح قائمة ثنائية الأبعاد
مصفوفة = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
مسطحة = [رقم for صف in مصفوفة for رقم in صف]
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

# تعبير شرطي
أرقام = [-2, -1, 0, 1, 2]
مطلقة = [س if س >= 0 else -س for س in أرقام]
# [2, 1, 0, 1, 2]

القوائم المتداخلة (ثنائية الأبعاد)

Python
# إنشاء قوائم ثنائية الأبعاد (مصفوفات)
مصفوفة = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

# الوصول للعناصر
print(مصفوفة[0])      # [1, 2, 3] (الصف الأول)
print(مصفوفة[1][2])   # 6 (صف 1، عمود 2)
print(مصفوفة[-1][-1]) # 9 (العنصر الأخير)

# التكرار على قائمة ثنائية الأبعاد
for صف in مصفوفة:
    for عنصر in صف:
        print(عنصر, end=" ")
    print()

# مع enumerate للفهارس
for ص, صف in enumerate(مصفوفة):
    for س, قيمة in enumerate(صف):
        print(f"[{ص}][{س}] = {قيمة}")

# إنشاء مصفوفة بالفهم
أصفار = [[0 for _ in range(3)] for _ in range(3)]
# [[0, 0, 0], [0, 0, 0], [0, 0, 0]]

# خطأ شائع: المراجع المشتركة!
# خطأ: كل الصفوف تشترك في نفس القائمة!
خاطئ = [[0] * 3] * 3
خاطئ[0][0] = 1  # يغير كل الصفوف!
print(خاطئ)  # [[1, 0, 0], [1, 0, 0], [1, 0, 0]]

# صحيح: كل صف مستقل
صحيح = [[0] * 3 for _ in range(3)]
صحيح[0][0] = 1  # يغير الصف الأول فقط
print(صحيح)  # [[1, 0, 0], [0, 0, 0], [0, 0, 0]]
تعيين القائمة يُنشئ مرجعاً

تعيين قائمة لمتغير آخر يُنشئ مرجعاً، ليس نسخة:

أ = [1, 2, 3]
ب = أ        # ب تشير لنفس القائمة
ب[0] = 99
print(أ)     # [99, 2, 3] - أ تغيرت أيضاً!

# لإنشاء نسخة مستقلة:
ج = أ.copy()     # أو أ[:]
ج[0] = 1
print(أ)     # [99, 2, 3] - أ لم تتغير

تحدي: إحصائيات القائمة

أنشئ دالة تأخذ قائمة أرقام وترجع:

  • المجموع، المتوسط، الأدنى، الأقصى
  • عدد الأرقام الموجبة والسالبة
  • القائمة مرتبة تنازلياً
أظهر الحل
def إحصائيات_القائمة(أرقام):
    if not أرقام:
        return "قائمة فارغة"

    المجموع = sum(أرقام)
    المتوسط = المجموع / len(أرقام)
    الأدنى = min(أرقام)
    الأقصى = max(أرقام)

    موجبة = len([ر for ر in أرقام if ر > 0])
    سالبة = len([ر for ر in أرقام if ر < 0])

    مرتبة_تنازلي = sorted(أرقام, reverse=True)

    return {
        "المجموع": المجموع,
        "المتوسط": round(المتوسط, 2),
        "الأدنى": الأدنى,
        "الأقصى": الأقصى,
        "عدد_الموجبة": موجبة,
        "عدد_السالبة": سالبة,
        "مرتبة_تنازلي": مرتبة_تنازلي
    }

# اختبار
أرقام = [5, -3, 8, -1, 0, 7, -2, 4]
إحصائيات = إحصائيات_القائمة(أرقام)

for مفتاح, قيمة in إحصائيات.items():
    print(f"{مفتاح}: {قيمة}")

تحدي: إزالة التكرارات

اكتب دالة تزيل التكرارات من قائمة مع الحفاظ على الترتيب الأصلي.

أظهر الحل
def إزالة_التكرارات(عناصر):
    شوهدت = set()
    النتيجة = []

    for عنصر in عناصر:
        if عنصر not in شوهدت:
            شوهدت.add(عنصر)
            النتيجة.append(عنصر)

    return النتيجة

# طريقة بديلة باستخدام dict (تحافظ على الترتيب في بايثون 3.7+)
def إزالة_التكرارات_v2(عناصر):
    return list(dict.fromkeys(عناصر))

# اختبار
أرقام = [1, 3, 2, 3, 1, 4, 2, 5]
print(إزالة_التكرارات(أرقام))     # [1, 3, 2, 4, 5]
print(إزالة_التكرارات_v2(أرقام))  # [1, 3, 2, 4, 5]

النقاط الرئيسية

ملخص
  • القوائم مجموعات مرتبة وقابلة للتعديل
  • الفهرسة: موجبة من البداية (0)، سالبة من النهاية (-1)
  • التقطيع: قائمة[بداية:نهاية:خطوة]
  • الدوال الرئيسية: append()، extend()، insert()، remove()، pop()، sort()
  • فهم القوائم: [تعبير for عنصر in تسلسل if شرط]
  • التعيين يُنشئ مرجعاً، ليس نسخة
  • استخدم copy() أو [:] للنسخ السطحي

في الدرس القادم، سنستكشف الصفوف (Tuples) - تسلسلات غير قابلة للتعديل!