الوحدة 3 • الدرس 9

الصفوف (Tuples)

تعلم كيفية استخدام الصفوف - القوائم الثابتة غير القابلة للتغيير

⏱️ 20 دقيقة 📊 متوسط 🔒 هياكل البيانات الثابتة

📦 ما هي الصفوف؟

الصفوف (Tuples) هي مجموعات مرتبة من العناصر، تشبه القوائم لكنها غير قابلة للتغيير بعد إنشائها. هذا يجعلها مثالية للبيانات التي لا يجب تعديلها.

💡
متى نستخدم الصفوف؟

عندما نريد حماية البيانات من التعديل، أو عند استخدام البيانات كمفاتيح في القواميس.

إنشاء الصفوف

Python طرق إنشاء الصفوف
# صف بسيط
إحداثيات = (10, 20)
print(إحداثيات)  # (10, 20)

# صف متعدد العناصر
ألوان = ("أحمر", "أخضر", "أزرق")
print(ألوان)  # ('أحمر', 'أخضر', 'أزرق')

# صف بدون أقواس (tuple packing)
أبعاد = 100, 200, 300
print(أبعاد)  # (100, 200, 300)

# صف عنصر واحد (لاحظ الفاصلة)
عنصر_واحد = ("قيمة",)
print(عنصر_واحد)  # ('قيمة',)

# صف فارغ
صف_فارغ = ()
print(صف_فارغ)  # ()

# من قائمة
من_قائمة = tuple([1, 2, 3])
print(من_قائمة)  # (1, 2, 3)
⚠️
تنبيه مهم!

لإنشاء صف من عنصر واحد، يجب وضع فاصلة بعد العنصر: ("قيمة",) وليس ("قيمة")

🎯 الوصول إلى العناصر

Python الفهرسة والتقطيع
أشهر = ("يناير", "فبراير", "مارس", "أبريل", "مايو")

# الفهرسة الإيجابية
print(أشهر[0])   # يناير
print(أشهر[2])   # مارس

# الفهرسة السلبية
print(أشهر[-1])  # مايو
print(أشهر[-2])  # أبريل

# التقطيع (Slicing)
print(أشهر[1:4])   # ('فبراير', 'مارس', 'أبريل')
print(أشهر[:3])    # ('يناير', 'فبراير', 'مارس')
print(أشهر[2:])    # ('مارس', 'أبريل', 'مايو')
print(أشهر[::2])   # ('يناير', 'مارس', 'مايو')

📤 تفكيك الصفوف (Unpacking)

من أقوى ميزات الصفوف هي القدرة على تفكيكها إلى متغيرات متعددة بسهولة.

Python تفكيك الصفوف
# تفكيك أساسي
نقطة = (5, 10)
س, ص = نقطة
print(f"س = {س}, ص = {ص}")  # س = 5, ص = 10

# تفكيك متعدد
شخص = ("أحمد", 25, "القاهرة")
الاسم, العمر, المدينة = شخص
print(f"{الاسم} عمره {العمر} من {المدينة}")

# تبادل القيم
أ = 10
ب = 20
أ, ب = ب, أ
print(f"أ = {أ}, ب = {ب}")  # أ = 20, ب = 10

# التفكيك الموسع مع *
أرقام = (1, 2, 3, 4, 5)
أول, *وسط, أخير = أرقام
print(f"أول: {أول}")      # أول: 1
print(f"وسط: {وسط}")      # وسط: [2, 3, 4]
print(f"أخير: {أخير}")    # أخير: 5

# تجاهل عناصر معينة
بيانات = ("سارة", 30, "مهندسة", "الرياض")
اسم, _, مهنة, _ = بيانات
print(f"{اسم} تعمل {مهنة}")
نصيحة:

استخدم _ كمتغير للقيم التي لا تحتاجها عند تفكيك الصفوف.

🔧 دوال الصفوف

لأن الصفوف غير قابلة للتغيير، لديها دالتان فقط:

Python count و index
درجات = (85, 90, 85, 78, 85, 92)

# count - عدد مرات ظهور عنصر
تكرار_85 = درجات.count(85)
print(f"تكرار 85: {تكرار_85}")  # تكرار 85: 3

# index - موقع أول ظهور
موقع_90 = درجات.index(90)
print(f"موقع 90: {موقع_90}")  # موقع 90: 1

# البحث في نطاق محدد
موقع_85_بعد_2 = درجات.index(85, 2)  # البحث بعد الموقع 2
print(f"موقع 85 بعد الموقع 2: {موقع_85_بعد_2}")  # 2

count(x)

يعيد عدد مرات ظهور العنصر x

index(x)

يعيد موقع أول ظهور للعنصر x

عمليات على الصفوف

Python عمليات متنوعة
# الدمج
صف1 = (1, 2, 3)
صف2 = (4, 5, 6)
مدمج = صف1 + صف2
print(مدمج)  # (1, 2, 3, 4, 5, 6)

# التكرار
مكرر = (0,) * 5
print(مكرر)  # (0, 0, 0, 0, 0)

# الطول
أيام = ("السبت", "الأحد", "الاثنين")
print(len(أيام))  # 3

# الفحص
print("الأحد" in أيام)      # True
print("الجمعة" not in أيام) # True

# الحد الأقصى والأدنى
أرقام = (45, 12, 78, 23, 56)
print(max(أرقام))  # 78
print(min(أرقام))  # 12
print(sum(أرقام))  # 214

# الفرز (يعيد قائمة)
مرتب = sorted(أرقام)
print(مرتب)  # [12, 23, 45, 56, 78]

# الصف المعكوس
معكوس = tuple(reversed(أيام))
print(معكوس)  # ('الاثنين', 'الأحد', 'السبت')

🏷️ الصفوف المسماة (Named Tuples)

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

Python namedtuple
from collections import namedtuple

# إنشاء نوع صف مسمى
نقطة = namedtuple('نقطة', ['س', 'ص'])

# إنشاء كائن
موقع = نقطة(10, 20)
print(موقع)        # نقطة(س=10, ص=20)
print(موقع.س)      # 10
print(موقع.ص)      # 20
print(موقع[0])     # 10 (الوصول بالفهرس أيضاً)

# مثال: بيانات طالب
طالب = namedtuple('طالب', ['اسم', 'عمر', 'معدل'])

طالب1 = طالب("محمد", 20, 3.5)
طالب2 = طالب("فاطمة", 22, 3.8)

print(f"{طالب1.اسم} معدله {طالب1.معدل}")
print(f"{طالب2.اسم} معدلها {طالب2.معدل}")

# تحويل قاموس إلى صف مسمى
بيانات = {'اسم': 'أحمد', 'عمر': 21, 'معدل': 3.6}
طالب3 = طالب(**بيانات)
print(طالب3)

⚖️ الصفوف مقابل القوائم

الخاصية الصفوف (Tuple) القوائم (List)
الرمز () []
قابلية التغيير ❌ غير قابلة ✅ قابلة
الأداء ⚡ أسرع 🐢 أبطأ
استخدام كمفتاح ✅ نعم ❌ لا
حماية البيانات ✅ محمية ❌ قابلة للتعديل
Python استخدام الصف كمفتاح
# الصفوف يمكن استخدامها كمفاتيح في القواميس
مواقع = {}
مواقع[(0, 0)] = "البداية"
مواقع[(10, 20)] = "نقطة أ"
مواقع[(30, 40)] = "نقطة ب"

print(مواقع[(10, 20)])  # نقطة أ

# القوائم لا يمكن استخدامها كمفاتيح
# مواقع[[0, 0]] = "خطأ"  # TypeError!

💼 أمثلة عملية

Python إرجاع قيم متعددة من دالة
def إحصائيات(أرقام):
    """تحسب إحصائيات متعددة وتعيدها كصف"""
    الطول = len(أرقام)
    المجموع = sum(أرقام)
    المتوسط = المجموع / الطول
    الأكبر = max(أرقام)
    الأصغر = min(أرقام)
    return الأكبر, الأصغر, المتوسط, المجموع

درجات = [85, 90, 78, 92, 88]
أعلى, أدنى, معدل, مجموع = إحصائيات(درجات)

print(f"أعلى درجة: {أعلى}")
print(f"أدنى درجة: {أدنى}")
print(f"المعدل: {معدل:.1f}")
print(f"المجموع: {مجموع}")
Python الإحداثيات والهندسة
import math

def المسافة(نقطة1, نقطة2):
    """تحسب المسافة بين نقطتين"""
    س1, ص1 = نقطة1
    س2, ص2 = نقطة2
    return math.sqrt((س2-س1)**2 + (ص2-ص1)**2)

نقطة_أ = (0, 0)
نقطة_ب = (3, 4)

المسافة_بينهما = المسافة(نقطة_أ, نقطة_ب)
print(f"المسافة: {المسافة_بينهما}")  # المسافة: 5.0

# مثلث كأضلاع
مثلث = (نقطة_أ, نقطة_ب, (6, 0))
print(f"رؤوس المثلث: {مثلث}")

🎯 تحديات تطبيقية

التحدي 1 سهل

تفكيك بيانات الموظف

لديك صف يحتوي على بيانات موظف. فككه واطبع المعلومات بشكل منسق.

موظف = ("خالد", "مبرمج", 5000, "الرياض")
# اطبع: "خالد يعمل مبرمج براتب 5000 في الرياض"
عرض الحل
موظف = ("خالد", "مبرمج", 5000, "الرياض")
الاسم, الوظيفة, الراتب, المدينة = موظف
print(f"{الاسم} يعمل {الوظيفة} براتب {الراتب} في {المدينة}")
التحدي 2 متوسط

دالة الحد الأقصى والأدنى

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

# أكمل الدالة
def حدود(أرقام):
    # أعد (الأكبر, الأصغر)
    pass

نتيجة = حدود([5, 2, 8, 1, 9])
print(نتيجة)  # (9, 1)
عرض الحل
def حدود(أرقام):
    return (max(أرقام), min(أرقام))

نتيجة = حدود([5, 2, 8, 1, 9])
print(نتيجة)  # (9, 1)

الأكبر, الأصغر = نتيجة
print(f"الأكبر: {الأكبر}, الأصغر: {الأصغر}")
التحدي 3 متقدم

نظام تسجيل الطلاب

أنشئ صفوف مسماة لتمثيل بيانات الطلاب، ثم اكتب دالة تجد الطالب الأعلى معدلاً.

from collections import namedtuple

# أنشئ صف مسمى للطالب
# ثم أنشئ قائمة من 3 طلاب
# واكتب دالة تجد الأعلى معدلاً
عرض الحل
from collections import namedtuple

# إنشاء صف مسمى
طالب = namedtuple('طالب', ['اسم', 'معدل', 'تخصص'])

# قائمة الطلاب
طلاب = [
    طالب("أحمد", 3.5, "هندسة"),
    طالب("سارة", 3.9, "طب"),
    طالب("محمد", 3.7, "علوم")
]

def الأعلى_معدلاً(قائمة_طلاب):
    return max(قائمة_طلاب, key=lambda ط: ط.معدل)

المتفوق = الأعلى_معدلاً(طلاب)
print(f"الطالب المتفوق: {المتفوق.اسم}")
print(f"المعدل: {المتفوق.معدل}")
print(f"التخصص: {المتفوق.تخصص}")