القوائم lists في بايثون
تمتلك بايثون عددًا من أنواع البيانات المركبة والتي تستخدم لتجميع القيم الأخرى مع بعضها البعض. أوسع هذه الأنواع وأكثرها شمولًا هو القوائم، والتي يمكن كتابتها كقائمة من القيم (العناصر) المفصولة عن بعضها البعض بفواصل (،)
ومحاطة بأقواس مربعة. يمكن للقوائم أن تتضمّن أنواعًا مختلفة، ولكن عادة ما تكون العناصر كلها من النوع نفسه.
>>> squares = [1, 4, 9, 16, 25]
>>> squares
[1, 4, 9, 16, 25]
كما هو الحال مع السلاسل النصية (والأنواع الأخرى من التسلسلات [sequence])، يمكن فهرسة القوائم واقتطاع أجزاء منها:
>>> squares[0] # تعيد عملية الفهرسة العنصر المطلوب
1
>>> squares[-1]
25
>>> squares[-3:] # تعيد عملية الاقتطاع قائمة جديدة
[9, 16, 25]
تعيد جميع عمليات الاقتطاع قائمة جديدة تتضمن العناصر المطلوبة، وهذا يعني أن عملية الاقتطاع التالية تعيد نسخة جديدة من القائمة:
>>> squares[:]
[1, 4, 9, 16, 25]
تدعم القوائم عمليات مثل الربط:
>>> squares + [36, 49, 64, 81, 100]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
ولكن على العكس من السلاسل النصية فإنّ القوائم قابلة للتعديل (mutable)، أي يمكن تعديل محتويات حسب الحاجة:
>>> cubes = [1, 8, 27, 65, 125] # هنالك خطأ ما
>>> 4 ** 3 # مكعب الرقم 4 يساوي 64 وليس 65
64
>>> cubes[3] = 64 # استبدل القيمة الخاطئة
>>> cubes
[1, 8, 27, 64, 125]
يمكن أيضًا إضافة عناصر جديدة إلى نهاية القائمة، وذلك بواسطة التابع append()
:
>>> cubes.append(216) # أضف مكعب الرقم 6
>>> cubes.append(7 ** 3) # ومكعب الرقم 7
>>> cubes
[1, 8, 27, 64, 125, 216, 343]
يمكن الإسناد إلى الأجزاء المقتطعة من القائمة، ويمكن لهذه العملية أن تغير طول القائمة أو تحذف عناصرها بالكامل:
>>> letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> letters
['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> # استبدال بعض القيم
>>> letters[2:5] = ['C', 'D', 'E']
>>> letters
['a', 'b', 'C', 'D', 'E', 'f', 'g']
>>> # ستحذف القيم الآن
>>> letters[2:5] = []
>>> letters
['a', 'b', 'f', 'g']
>>> # إفراغ القائمة وذلك بحذف جميع العناصر وتحويلها إلى قائمة فارغة
>>> letters[:] = []
>>> letters
[]
يمكن تنفيذ الدالة len()
على القوائم أيضًا للحصول على عدد العناصر في القائمة:
>>> letters = ['a', 'b', 'c', 'd']
>>> len(letters)
4
يمكن إنشاء قوائم متداخلة (أي إنشاء قائمة تحتوي على قوائم أخرى)، فمثلًا:
>>> a = ['a', 'b', 'c']
>>> n = [1, 2, 3]
>>> x = [a, n]
>>> x
[['a', 'b', 'c'], [1, 2, 3]]
>>> x[0]
['a', 'b', 'c']
>>> x[0][1]
'b'
List Comprehensions
تقدّم List comprehensions طريقة مختصرة لإنشاء القوائم، ومن التطبيقات الشائعة هي إنشاء قوائم جديدة يكون فيها كل عنصر نتيجة لبعض العمليات المطبقة على كل عنصر في تسلسل آخر، أو إنشاء تسلسل فرعي يضمّ العناصر التي تطابق شرطًا معيّنًا.
لنفترض على سبيل المثال أنّنا نرغب في إنشاء قائمة بمربعات الأرقام، مثل:
>>> squares = []
>>> for x in range(10):
... squares.append(x**2)
...
>>> squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
لاحظ أنّ الشيفرة السابقة تنشئ (أو تعيد كتابة) المتغيّر x
والذي يبقى موجودًا بعد انتهاء الحلقة التكرارية. يمكن حساب قائمة مربّعات الأرقام دون أي مشاكل باستخدام:
squares = list(map(lambda x: x**2, range(10)))
أو باستخدام الصيغة المكافئة التالية وهي صيغة مختصرة وسهلة القراءة:
squares = [x**2 for x in range(10)]
تتكوّن list comprehensions من أقواس تضمّ تعبيرًا تتبعه عبارة for
ويمكن أن تليها مجموعة من تعابير if
أو for
. تكون النتيجة قائمة جديدة تنشأ من معالجة التعبير في سياق عبارات for
و if
التي تليه.
في المثال التالي تجمع list comprehension عناصر قائمتين مختلفتين إن كانت هذه العناصر غير متساوية:
>>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
الشيفرة السابقة مكافئة للشيفرة التالية:
>>> combs = []
>>> for x in [1,2,3]:
... for y in [3,1,4]:
... if x != y:
... combs.append((x, y))
...
>>> combs
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
لاحظ أنّ ترتيب عبارتي for
و if
متطابق في كلا المثالين السابقين.
عند الحاجة إلى استخدام الصفوف (tuples) (مثل (x, y)
في المثال السابق) فيجب أن يحاط التعبير بأقواس.
>>> vec = [-4, -2, 0, 2, 4]
>>> # إنشاء قائمة جديدة مع مضاعفة الأرقام
>>> [x*2 for x in vec]
[-8, -4, 0, 4, 8]
>>> # إنشاء قائمة جديدة مع استبعاد الأرقام السالبة
>>> [x for x in vec if x >= 0]
[0, 2, 4]
>>> # تطبيق دالة على جميع العناصر
>>> [abs(x) for x in vec]
[4, 2, 0, 2, 4]
>>> # استدعاء تابع مع كل العناصر
>>> freshfruit = [' banana', ' loganberry ', 'passion fruit ']
>>> [weapon.strip() for weapon in freshfruit]
['banana', 'loganberry', 'passion fruit']
>>> # إنشاء قائمة من صفوف ثنائية (الرقم، مربع الرقم)
>>> [(x, x**2) for x in range(6)]
[(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]
>>> # يجب أن يحاط الصفّ بأقواس، وإلا تطلق اللغة خطأً
>>> [x, x**2 for x in range(6)]
File "<stdin>", line 1, in <module>
[x, x**2 for x in range(6)]
^
SyntaxError: invalid syntax
>>> # دمج القوائم باستخدام عبارتين تكراريتين
>>> vec = [[1,2,3], [4,5,6], [7,8,9]]
>>> [num for elem in vec for num in elem]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
يمكن أن تتضمن list comprehensions تعابير معقّدة ودوال متداخلة:
>>> from math import pi
>>> [str(round(pi, i)) for i in range(1, 6)]
['3.1', '3.14', '3.142', '3.1416', '3.14159']
List comprehensions متشعبة
يمكن لأول تعبير في list comprehension أن يكون تعبيرًا عامًّا، ويمكن أن يكون list comprehension آخر أيضًا.
يقدّم المثال التالي مصفوفة (matrix) بأبعاد 3×4
، وذلك باستخدام قائمة تتضمن 3
قوائم كل واحدة منها مكوّنة من 4
عناصر:
>>> matrix = [
... [1, 2, 3, 4],
... [5, 6, 7, 8],
... [9, 10, 11, 12],
... ]
ويمكن الاستفادة من list comprehensions في الحصول على منقولة المصفوفة (transpose):
>>> [[row[i] for row in matrix] for i in range(4)]
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
وكما رأينا مسبقًا فإنّ list comprehension المتداخلة تُعالج في سياق عبارة for
التي تليها، لذا فإنّ المثال السابق مكافئ للمثال التالي:
>>> transposed = []
>>> for i in range(4):
... transposed.append([row[i] for row in matrix])
...
>>> transposed
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]
والمثال السابق بدوره مكافئ لما يلي:
>>> transposed = []
>>> for i in range(4):
... # تستخدم الأسطر الثلاثة التالية listcomp المتداخلة
... transposed_row = []
... for row in matrix:
... transposed_row.append(row[i])
... transposed.append(transposed_row)
...
>>> transposed
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
ينصح باستخدام الدوال الداخلية بدلًا من عبارات التحكّم في التنفيذ المعقّدة، فعلى سبيل المثال يمكن تأدية العمليات السابقة باستخدام الدالة zip()
:
>>> list(zip(*matrix))
[(1, 5, 9), (2, 6, 10), (3, 7, 11), (4, 8, 12)]
راجع فك تحزيم قائمة الوسائط للمزيد من المعلومات حول علامة (*)
في السطر الأول من المثال السابق.
الدّالة list()
يُمكن تحويل الكائنات القابلة للتّكرار إلى قوائم عبر استخدام الدّالة list()
:
>>> list(range(1, 3))
[1, 2]
>>> list('ABCD')
['A', 'B', 'C', 'D']
>>> list((1, 2, 3))
[1, 2, 3]
الدوال التابعة للكائن list
list.sort()
تفرز هذه الدالة القائمة في مكانها وذلك بإجراء مقارنة بين عناصر القائمة بواسطة العامل <
فقط.
مصادر
- صفحتا An informal introduction to python و Built-in types في توثيق بايثون الرسمي.
- قسم الدالة list في صفحة Functions في توثيق Python الرسمي.