المسارات
/
Python
Python
/
المنهج
/
طُرق المصفوفات
طُ

طُرق المصفوفات في Python

70 تمرينًا

نبذة عن طُرق المصفوفات

النوع list مجموعة قابلة للتغيير من العناصر في تسلسل. وكمعظم المجموعات (انظر الأنواع المدمجة tuple وdict وset)، تستطيع المصفوفات أن تحمل مراجع إلى أي نوع بيانات (أو عدة أنواع)، بما في ذلك مصفوفات أخرى. وتُعدّ تسلسلًا في Python، ويمكن نسخها كاملة أو جزئيًا عبر تدوين الشرائح. وكأي تسلسل، يمكن الإشارة إلى العناصر داخل lists برقم 0-based index من اليسار، أو برقم -1-based index من اليمين.

تدعم المصفوفات عمليات التسلسل الشائعة والقابلة للتغيير على حد سواء، مثل min(<list>)/max(<list>) و<list>.index() و<list>.append() و<list>.reverse(). ويمكن المرور على العناصر باستخدام التركيب for item in <list>، وfor index, item in enumerate(<list>) عند الحاجة إلى العنصر وفهرسه معًا.

توفّر Python العديد من الطرق المفيدة للتعامل مع المصفوفات.

ولأن المصفوفات قابلة للتغيير، فإن طرق المصفوفات تعدّل كائن المصفوفة الأصلي الذي يُمرَّر إلى الطريقة. وإذا كان التعديل غير مرغوب فيه، فيجب إنشاء shallow copy (كحد أدنى) من list الأصلي عبر slice أو <list>.copy().

إضافة العناصر

يمكن إضافة عناصر إلى نهاية مصفوفة موجودة عبر <list>.append(<item>):

>>> numbers = [1, 2, 3]
>>> numbers.append(9)

>>> numbers
[1, 2, 3, 9]

وبدلًا من الإضافة في النهاية، تضيف <list>.insert(<index>, <item>) العنصر إلى فهرس محدد داخل المصفوفة. <index> هو فهرس العنصر الذي تريد أن يظهر العنصر الجديد قبله. أما <item> فهو العنصر المراد إدراجه.

ملاحظة: إذا كان <index> يساوي 0، فسيُضاف العنصر إلى بداية المصفوفة. وإذا كان <index> أكبر من الفهرس الأخير في المصفوفة، فسيُضاف العنصر في الموضع الأخير، وهو ما يعادل استخدام <list>.append(<item>).

>>> numbers = [1, 2, 3]
>>> numbers.insert(0, -2)

>>> numbers
[-2, 1, 2, 3]

>>> numbers.insert(1, 0)

>>> numbers
[-2, 0, 1, 2, 3]

يمكن دمج iterable مع مصفوفة موجودة (بضمّ الاثنين معًا) عبر <list>.extend(<iterable>). ستقوم <list>.extend(<iterable>) بـ_فكّ_ الكائن القابل للتكرار المُمرَّر، مضيفةً عناصره بالترتيب نفسه إلى نهاية المصفوفة الهدف. واستخدام <list>.append(<item>) في هذه الحالة سيضيف الكائن القابل للتكرار بأكمله كـ_عنصر واحد_.

>>> numbers = [1, 2, 3]
>>> other_numbers = [5, 6, 7]

>>> numbers.extend(other_numbers)

>>> numbers
[1, 2, 3, 5, 6, 7]

>>> numbers.extend([8, 9])

>>> numbers
[1, 2, 3, 5, 6, 7, 8, 9]

إزالة العناصر

يمكن استخدام <list>.remove(<item>) لإزالة عنصر من المصفوفة. وسترفع <list>.remove(<item>) الخطأ ValueError إذا لم يكن العنصر موجودًا في المصفوفة.

>>> numbers = [1, 2, 3]
>>> numbers.remove(2)

>>> numbers
[1, 3]

# Trying to remove a value that is not in the list throws a ValueError.
>>> numbers.remove(0)
ValueError: list.remove(x): x not in list

وبدلًا من ذلك، ستُزيل الطريقة <list>.pop(<index>) العنصر وتُرجعه بـreturn لاستخدامه.

تأخذ <list>.pop(<index>) معاملًا اختياريًا واحدًا: وهو index العنصر المراد إزالته وإرجاعه. وإذا لم تُحدَّد الوسيطة الاختيارية <index>، فسيُزال آخر عنصر في المصفوفة ويُرجَع. وإذا كان <index> رقمًا أكبر من الفهرس الأخير في المصفوفة، فسيُرفع IndexError.

>>> numbers = [1, 2, 3]
>>> numbers.pop(0)
1

>>> numbers
[2, 3]
>>> numbers.pop()
3

>>> numbers
[2]

# This will throw an error because there is only index 0.
>>> numbers.pop(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: pop index out of range

يمكن إزالة كل العناصر من list عبر <list>.clear(). وهي لا تأخذ أي معاملات.

>>> numbers = [1, 2, 3]
>>> numbers.clear()

>>> numbers
[]

العكس وإعادة الترتيب

يمكن عكس ترتيب عناصر المصفوفة في مكانها باستخدام <list>.reverse(). وهذا سيعدّل المصفوفة الأصلية.

>>> numbers = [1, 2, 3]
>>> numbers.reverse()

>>> numbers
[3, 2, 1]

يمكن إعادة ترتيب المصفوفة في مكانها بمساعدة <list>.sort(). ترتيب الفرز الافتراضي تصاعدي من اليسار. وتقدّم وثائق Python نصائح وتقنيات إضافية للفرز.

Note

من عام 2002 إلى عام 2022، استخدمت Python خوارزمية تُسمى Timsort داخليًا لترتيب المصفوفات، لكنها انتقلت إلى Powersort بدءًا من Python 3.11 فصاعدًا. يمكنك قراءة مزيد من التفاصيل والنقاش حول هذا التغيير من فريق Python الأساسي في المشكلة رقم 78742 على GitHub.

وللاطلاع على التفاصيل التقنية للخوارزمية، راجع الورقة البحثية لـ J. Ian Munro وSebastian Wild بعنوان Nearly-Optimal Mergesorts: Fast, Practical Sorting Methods That Optimally Adapt to Existing Runs

>>> names = ["Tony", "Natasha", "Thor", "Bruce"]

# The default sort order is *ascending*.
>>> names.sort()

>>> names
["Bruce", "Natasha", "Thor", "Tony"]

لفرز المصفوفة بترتيب تنازلي، مرّر الوسيطة reverse=True إلى الطريقة:

>>> names = ["Tony", "Natasha", "Thor", "Bruce"]
>>> names.sort(reverse=True)

>>> names
["Tony", "Thor", "Natasha", "Bruce"]

في الحالات التي لا يكون فيها تعديل list الأصلي مرغوبًا، يمكن استخدام الدالتين المدمجتين sorted() وreversed(). ستُرجع sorted(<list>) نسخة مفروزة، وتأخذ المعاملات نفسها التي تأخذها <list>.sort(). وتُرجع reversed(<list>) مُكرِّرًا يعطي عناصر المصفوفة بترتيب معكوس. وسيُغطّى موضوع Iterators بالتفصيل في تمرين آخر.

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

يمكن معرفة عدد مرات ظهور عنصر في المصفوفة بمساعدة <list>.count(<item>). وهي تُرجع العدد الإجمالي لمرات ظهور <item> كعنصر في المصفوفة.

>>> items = [1, 4, 7, 8, 2, 9, 2, 1, 1, 0, 4, 3]

>>> items.count(1)
3

إيجاد فهرس العناصر

ستُرجع <list>.index(<item>) رقم فهرس أول ظهور للعنصر المُمرَّر. وإذا لم يكن هناك أي ظهور، فسيُرفع ValueError. والفهرسة 0-based من اليسار، أي أن موضع العنصر الأول هو الفهرس 0. وتُدعم الفهرسة من اليمين أيضًا، بدءًا من الفهرس -1.

>>> items = [7, 4, 1, 0, 2, 5]
>>> items.index(4)
1

>>> items.index(10)
ValueError: 10 is not in list

وسيؤدي تمرير فهرسي start وend إلى البحث ضمن قسم محدد من المصفوفة:

>>> names = ["Tina", "Leo", "Thomas", "Tina", "Emily", "Justin"]
>>> names.index("Tina")
0

>>> names.index("Tina", 2, 5)
3

وإذا لم تكن بحاجة إلى الموضع الدقيق للعنصر، فإن العامل in المدمج أكثر كفاءة للتحقق من العضوية.

>>> names = ["Tina", "Leo", "Thomas", "Tina", "Emily", "Justin"]

>>> "Thomas" in names
True

إنشاء النسخ

تذكّر أن المتغيرات في Python أسماء تشير إلى كائنات أساسية. ويمكن ربط الأسماء بكائنات مختلفة أو إعادة ربطها بها طوال عمر البرنامج. وإنشاء كائن list وإسناده إلى اسم متغير جديد لا ينسخ الكائن ولا أيًّا من بياناته المُشار إليها. وسيشير الاسم الجديد والاسم القديم معًا إلى كائن list نفسه. وإضافة إلى ذلك، فإن المصفوفات كائنات من نوع حاوٍ: فللحفاظ على المساحة، لا تحتفظ الحاويات إلا بـ_مراجع_ إلى العناصر الأعضاء، لا بالعناصر نفسها. وقد يكون لهذا "التحسين" أثر غير مقصود على من لا ينتبه.

ستُنشئ <list>.copy() كائن list جديدًا، لكنها لن تُنشئ كائنات جديدة لـ_عناصر_ المصفوفة المُشار إليها، فالنسخة "سطحية". وعادةً تكفي shallow copy عندما تريد إضافة عناصر إلى أحد كائني list أو إزالتها منه دون تعديل الآخر. ولكن إذا كان هناك أي احتمال بأن تُعدَّل العناصر الأساسية لمصفوفة عن طريق الخطأ (وبالتالي تُعدَّل كل النسخ السطحية المرتبطة بها)، فيجب استخدام copy.deepcopy() في وحدة copy لإنشاء نسخة كاملة أو "عميقة" لـجميع المراجع والكائنات.

وللحصول على شرح مفصّل لسلوك الأسماء والقيم والمصفوفات والمصفوفات المتداخلة، ألقِ نظرة على هذه التدوينة الممتازة من Ned Batchelder، بعنوان Names and values: making a game board. كما تقدّم Shallow vs Deep Copying of Python Objects عرضًا جيدًا لاعتبارات النسخ.

تعديل عبر GitHub يفتح الرابط في نافذة أو علامة تبويب جديدة

تعلّم طُرق المصفوفات

التدريب مقفل

افتح 6 تمارين إضافية لممارسة طُرق المصفوفات