بنى المعطيات
حتى الآن حفظ كل متغيّر قيمة واحدة. لكن المحطة التي تقيس كل ساعة، والمختبر الذي يسجّل نتائج طلابه، والجهاز الذي يأخذ ألف عينة من إشارة، كلها تحتاج إلى حفظ قيم كثيرة معا والعودة إليها لاحقا. في هذا الفصل نتعرف إلى القائمة، وهي أكثر بنى المعطيات استعمالا في بايثون، وإلى الحلقة for التي تمر عليها، ثم نكتب بأنفسنا خوارزميات البحث والفرز.
- نبني قائمة، نصل إلى عناصرها بالمؤشّر والقصّ، ونغيّرها.
- نستعمل قائمة عدّادات وقائمة مُجمِّعات.
- نمر على القوائم بالحلقة
for، بالعناصر وبالمؤشّرات. - نستعمل عمليّات القائمة، ونبني قائمة من قوائم.
- نكتب بأنفسنا خوارزميات القيمة القصوى والدمج والفرز.
- نميّز بين القائمة والصفّ الثابت
tuple، ونعرف متى نختار كلا منهما.
6.1 مفهوم بنية المعطيات – היכרות עם המושג מבנה נתונים
في الفصل 4 قرأنا سلسلة قياسات بحلقة وحسبنا متوسطها. في كل دورة كانت القراءة الجديدة تحل مكان السابقة في المتغيّر نفسه. فإذا سألنا بعد الحلقة: أي القراءات أعلى من المتوسط؟ لم نجد جوابا، لأن القراءات ضاعت. لا نعرف المتوسط إلا في النهاية، وفي النهاية لم يبق لدينا سوى آخر قراءة.
r1 = 12.1
r2 = 11.6
r3 = 12.4
r4 = 11.9
average = (r1 + r2 + r3 + r4) / 4
if r1 > average:
print(r1)
if r2 > average:
print(r2)
if r3 > average:
print(r3)
if r4 > average:
print(r4)12.1 12.4
البرنامج صحيح، لكنه لا يكبر معنا. مئة قراءة تعني مئة متغيّر ومئة أمر شرطي. ولا يمكننا أن نترك عدد القراءات للمستخدم، لأن أسماء المتغيّرات تُكتب مسبقا في البرنامج.
البنية الأولى التي نتعلمها هي القائمة (רשימה). نكتب القيم بين قوسين مربعين، وتفصل بينها فواصل. وكل قيمة في البنية اسمها عنصر (איבר):
readings = [12.1, 11.6, 12.4, 11.9] print(readings) print(readings[0]) print(len(readings)) print(round(sum(readings) / len(readings), 2))
[12.1, 11.6, 12.4, 11.9] 12.1 4 12.0
الآن بقيت القراءات الأربع محفوظة تحت اسم واحد. وسنعود إلى سؤال القراءات الأعلى من المتوسط في البند 6.7، فنحلّه بأربعة أسطر مهما كان عددها. نتعلم في هذا الفصل بنيتين:
| البنية | كتابتها | هل تتغيّر بعد إنشائها؟ | مثال على استعمالها |
|---|---|---|---|
| القائمة list | [12.1, 11.6] | نعم: نضيف ونحذف ونغيّر | سجل قراءات يكبر مع الوقت |
| الصفّ الثابت tuple | (8, 12.4) | لا: تبقى كما أنشأناها | قراءة واحدة: ساعتها وجهدها معا |
(أ) ما مجموع القراءات؟
(ب) كم قراءة تزيد على المتوسط؟
(ج) ما أعلى قراءة؟
6.2 تهيئة القائمة والعمل على عناصرها – אתחול, רשימה ריקה, list, הדפסה, פעולות על איברים, רשימת מונים ורשימת צוברים (list)
نهيّئ قائمة بكتابة عناصرها بين قوسين مربعين. يمكن أن تكون العناصر أعدادا أو جملا نصية، ويمكن أن نخلط بينها، لكن القائمة التي عناصرها من نوع واحد أسهل في الاستعمال. نوع القائمة هو list، والدالة len تعطي عدد عناصرها.
volts = [12.1, 11.6, 12.4] parts = ["R1", "C4", "D2", "LED"] mixed = ["R1", 470, 0.25] print(volts) print(parts) print(mixed) print(type(volts), len(parts))
[12.1, 11.6, 12.4] ['R1', 'C4', 'D2', 'LED'] ['R1', 470, 0.25] <class 'list'> 4
القائمة الفارغة (רשימה ריקה) لا عناصر فيها، وطولها صفر. نكتبها [] أو list()، وهي نقطة البداية عندما نعبّئ القائمة أثناء تشغيل البرنامج. والدالة list تحوّل إلى قائمة أي قيمة يمكن المرور على أجزائها: جملة نصية، أو range، أو صفّا ثابتا، وسنتعرف إلى الأخيرين في هذا الفصل. أما العمليّة split من الفصل 5 فكانت تعطينا قائمة منذ البداية:
log = []
print(log, len(log))
print(list())
print(list("ADC"))
print(list(range(4)))
print("BAT=12.42;TMP=31.5".split(";"))[] 0 [] ['A', 'D', 'C'] [0, 1, 2, 3] ['BAT=12.42', 'TMP=31.5']
list(5) البرنامج. لقائمة فيها العدد وحده نكتب [5]. ولا نسمّي متغيّرا list، لأننا بذلك نفقد الدالة الجاهزة التي تحمل هذا الاسم.الدالة print تطبع القائمة كلها بقوسيها وفواصلها. وللوصول إلى عنصر نكتب مؤشّره بين قوسين مربعين، كما في الجمل النصية. والعنصر يتصرف مثل متغيّر عادي: نسند إليه قيمة جديدة ونحسب به. والدوال sum وmax وmin من الفصل 2 تعمل على القائمة كلها:
loads = [60, 100, 40] print(loads) print(loads[0], "W and", loads[1], "W") loads[1] = 75 loads[2] += 20 loads[0] = loads[0] * 2 print(loads) print(sum(loads), max(loads), min(loads))
[60, 100, 40] 60 W and 100 W [120, 75, 60] 255 120 60
هنا يظهر فرق أساسي عن الجملة النصية: القائمة تتغيّر في مكانها، أما حرف في جملة نصية فلا يمكن تغييره.
قائمة العدّادات – רשימת מונים:
في الفصل 4 عددنا بعدّاد واحد. فإذا أردنا أن نعدّ عشرة أشياء مختلفة احتجنا إلى عشرة عدّادات. قائمة العدّادات (רשימת מונים) تجمعها كلها في قائمة واحدة، وتبدأ كلها من الصفر. وفكرتها الجميلة أن القيمة التي نقرأها هي نفسها المؤشّر إلى عدّادها، فلا نحتاج إلى سلسلة شروط.
counts = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
digit = int(input("Digit (-1 to stop): "))
while digit != -1:
counts[digit] += 1
digit = int(input("Digit (-1 to stop): "))
print(counts)
print("Red bands:", counts[2])Digit (-1 to stop): 2 Digit (-1 to stop): 7 Digit (-1 to stop): 2 Digit (-1 to stop): 1 Digit (-1 to stop): 0 Digit (-1 to stop): 2 Digit (-1 to stop): -1 [1, 1, 3, 0, 0, 0, 0, 1, 0, 0] Red bands: 3
الأمر counts[digit] += 1 يزيد العدّاد المناسب مباشرة. لو كتبنا البرنامج بلا قائمة لاحتجنا إلى عشرة متغيّرات وعشرة شروط.
presses = [0, 0, 0, 0]
button = int(input("Button: "))
while button != 0:
presses[button - 1] += 1
button = int(input("Button: "))
print(presses)قائمة المُجمِّعات – רשימת צוברים:
قائمة المُجمِّعات (רשימת צוברים) تشبه قائمة العدّادات، لكننا نضيف إلى الخانة مقدارا ما بدل أن نضيف 1. المؤشّر يحدد إلى أين نضيف، والمُدخَل الثاني يحدد كم نضيف.
hours = [0, 0, 0]
tech = int(input("Technician (-1 to stop): "))
while tech != -1:
hours[tech] += float(input("Hours: "))
tech = int(input("Technician (-1 to stop): "))
print(hours)
print("Total:", sum(hours))Technician (-1 to stop): 0 Hours: 6.5 Technician (-1 to stop): 2 Hours: 8 Technician (-1 to stop): 0 Hours: 3 Technician (-1 to stop): -1 [9.5, 0, 8.0] Total: 17.5
الفني رقم 0 ورد مرتين، فجُمعت ساعاته في خانته.
6.3 البنية التسلسلية للقائمة والوصول بالمؤشّر – המבנה הסידורי של List, גישה לאיבר באמצעות אינדקס
عناصر القائمة مرتبة، ولكل عنصر رقم يدل على مكانه هو المؤشّر (אינדקס). يبدأ العد من الصفر كما في الجمل النصية، فالعنصر الأول مؤشّره 0، والأخير مؤشّره أقل من الطول بواحد. ويمكن أيضا أن نعدّ من النهاية بمؤشّر سالب: [-1] هو العنصر الأخير، و[-2] الذي قبله.
samples = [0.2, 1.4, 3.1, 4.8, 2.6] print(samples[0], samples[2], samples[4]) print(samples[-1], samples[-5]) samples[-1] = 0.0 print(samples)
0.2 3.1 2.6 2.6 0.2 [0.2, 1.4, 3.1, 4.8, 0.0]
المؤشّر السالب يعفينا من كتابة samples[len(samples) - 1]، ويعمل مهما كان طول القائمة، وهو يصلح للتغيير أيضا.
samples = [0.2, 1.4, 3.1, 4.8, 2.6] print(samples[5])
IndexError: list index out of range
while من الفصل 4 العينات التي تزيد على 2.5 V.samples = [0.2, 1.4, 3.1, 4.8, 2.6]
high = 0
i = 0
while i < len(samples):
if samples[i] > 2.5:
high += 1
i += 1
print("Above 2.5 V:", high)Above 2.5 V: 3
الشرط هو i < len(samples). لو كتبنا <= لأضفنا دورة بعد العنصر الأخير، ولتوقف البرنامج بالخطأ نفسه.
v = [5, 10, 15, 20, 25, 30]v[0]v[3]v[-1]v[-2]v[len(v) - 2]v[1] + v[-1]5 2 20 3 30 4 25 5 25 6 40 6.4 قصّ القوائم – חיתוך רשימות (slicing)
القصّ (חיתוך) يعطينا جزءا من القائمة كقائمة جديدة. نكتب s[start:stop:step]: نبدأ من المؤشّر start، ونتوقف قبل المؤشّر stop، ونتقدم بخطوة step. هذه هي القواعد نفسها التي عرفناها مع الجمل النصية:
s = [10, 20, 30, 40, 50, 60] print(s[1:4]) print(s[:3], s[3:]) print(s[-2:]) print(s[::2]) print(s[::-1]) print(s[2:100]) print(s[4:2]) print(s)
[20, 30, 40] [10, 20, 30] [40, 50, 60] [50, 60] [10, 30, 50] [60, 50, 40, 30, 20, 10] [30, 40, 50, 60] [] [10, 20, 30, 40, 50, 60]
- إذا حذفنا البداية نبدأ من أول القائمة، وإذا حذفنا النهاية نصل إلى آخرها. والخطوة
-1تعكس الترتيب. - القصّ لا يتوقف بخطأ: الحد
100خارج القائمة ومع ذلك يعمل، و[4:2]يعطي قائمة فارغة. - السطر الأخير يبيّن أن القصّ لا يغيّر القائمة الأصلية.
samples = [0.1, 0.9, 2.4, 2.5, 2.6, 2.4, 2.5] stable = samples[2:] print(stable) print(round(sum(stable) / len(stable), 2)) print(stable[::2])
[2.4, 2.5, 2.6, 2.4, 2.5] 2.48 [2.4, 2.6, 2.5]
الإسناد لا ينسخ القائمة:
b = a يصنع نسخة، فنغيّر b ونتوقع أن تبقى a كما هي. لكن هذا الأمر لا ينشئ قائمة ثانية، بل يعطي القائمة نفسها اسما آخر، وكل تغيير عبر أحد الاسمين يظهر في الآخر:a = [12, 9, 5] b = a b[0] = 99 print(a) print(b)
[99, 9, 5] [99, 9, 5]
حين نريد نسخة حقيقية نستعمل القصّ a[:]، أو الدالة list(a)، فتنشأ قائمة جديدة في الذاكرة:
a = [12, 9, 5] b = a[:] b[0] = 99 print(a) print(b)
[12, 9, 5] [99, 9, 5]
v = [1, 2, 3, 4, 5, 6]v[2:4]v[:2]v[4:]v[-3:-1]v[1::2]v[::-2][3, 4] 2 [1, 2] 3 [5, 6] 4 [4, 5] 5 [2, 4, 6] 6 [6, 4, 2] a = [1, 2, 3] b = a c = a[:] a[0] = 7 b[1] = 8 c[2] = 9 print(a) print(b) print(c)
6.5 إضافة عناصر إلى القائمة – הוספת איברים לרשימה
القائمة تكبر أثناء تشغيل البرنامج. العمليّة append تضيف عنصرا واحدا إلى النهاية، وهي الطريقة التي نستعملها في أغلب الأحيان. والمعامل + يصل قائمتين فينتج قائمة جديدة، و+= يضيف قائمة إلى نهاية القائمة نفسها. والمعامل * يكرر القائمة، وهذه أقصر طريقة لتهيئة قائمة عدّادات: بدل عشرة الأصفار في البند 6.2 نكتب [0] * 10.
log = [12.1] log.append(11.8) print(log) log = log + [11.9, 12.0] print(log) log += [12.2] print(log) print([0] * 5)
[12.1, 11.8] [12.1, 11.8, 11.9, 12.0] [12.1, 11.8, 11.9, 12.0, 12.2] [0, 0, 0, 0, 0]
loads = []
watts = float(input("Load W (0 to stop): "))
while watts != 0:
loads.append(watts)
watts = float(input("Load W (0 to stop): "))
print(loads)
print("Count:", len(loads))
print("Total:", sum(loads))Load W (0 to stop): 60 Load W (0 to stop): 100 Load W (0 to stop): 40.5 Load W (0 to stop): 0 [60.0, 100.0, 40.5] Count: 3 Total: 200.5
هذا النمط يتكرر كثيرا: قائمة فارغة قبل الحلقة، وappend داخلها. وهو يحل مشكلة بداية الفصل، إذ لم يعد عدد القراءات يُكتب مسبقا في البرنامج.
+ يصل قائمة بقائمة فقط، ولذلك نحيط العنصر الجديد بقوسين مربعين: log + 11.8 يوقف البرنامج، وlog + [11.8] صحيح. وكذلك لا ننشئ عنصرا جديدا بالإسناد إلى مؤشّر غير موجود: في قائمة فارغة يوقف log[0] = 12.1 البرنامج، والإضافة تتم بالعمليّة append.a = [1] a.append(2) b = a + [3] a += [4, 5] print(a) print(b) print([7] * 2 + [8])
6.6 استعمال range لتهيئة قائمة – שימוש ב-range לאתחול רשימה
الدالة range تولّد سلسلة أعداد صحيحة. نحوّلها إلى قائمة بالدالة list، فنحصل على قائمة طويلة من دون أن نكتب عناصرها. ولها ثلاثة أشكال:
| الأمر | عمله |
|---|---|
| range(stop) | من 0 حتى ما قبل stop |
| range(start, stop) | من start حتى ما قبل stop |
| range(start, stop, step) | من start حتى ما قبل stop، بخطوة step، وقد تكون سالبة |
print(list(range(5))) print(list(range(2, 8))) print(list(range(0, 50, 10))) print(list(range(5, 0, -1))) print(range(5))
[0, 1, 2, 3, 4] [2, 3, 4, 5, 6, 7] [0, 10, 20, 30, 40] [5, 4, 3, 2, 1] range(0, 5)
الحد stop لا يدخل في السلسلة أبدا، كما في القصّ. والسطر الأخير يبيّن أن range وحدها ليست قائمة، بل وصف لسلسلة أعداد تُولَّد عند الحاجة، ولذلك كتبنا list كي نراها.
freqs = list(range(100, 1100, 100)) print(freqs) channels = list(range(1, 9)) print(channels)
[100, 200, 300, 400, 500, 600, 700, 800, 900, 1000] [1, 2, 3, 4, 5, 6, 7, 8]
الحد الأعلى في السطر الأول هو 1100 كي يدخل 1000 في القائمة.
range تقبل أعدادا صحيحة فقط، ولذلك يوقف range(0, 1, 0.1) البرنامج: لا توجد خطوة عشرية.list(range(4))list(range(1, 4))list(range(0, 9, 3))list(range(10, 4, -2))[0, 1, 2, 3] 2 [1, 2, 3] 3 [0, 3, 6] 4 [10, 8, 6] 6.7 الحلقة for على عناصر القائمة – לולאת for העוברת על איברי רשימה (for)
في البند 6.3 مررنا على القائمة بالحلقة while: هيّأنا مؤشّرا، فحصناه، ورفعناه في كل دورة. هذا المرور شائع جدا، ولذلك توجد له حلقة خاصة هي for. نكتبها هكذا:
for item in sequence:
statement
statement
next_statement- في كل دورة يحصل المتغيّر
itemعلى العنصر التالي منsequence، بالترتيب، من الأول حتى الأخير. - لا نكتب مؤشّرا ولا شرطا ولا زيادة: الحلقة تتوقف وحدها عندما تنتهي العناصر.
- بعد السطر الأول نقطتان، وجسم الحلقة مزاح إلى الداخل، كما في
ifوwhile. - اسم المتغيّر نختاره نحن، ونختار اسما يدل على العنصر الواحد:
vأوscore.
volts = [12.1, 11.6, 12.4]
for v in volts:
print("Reading:", v)
print("Done")Reading: 12.1 Reading: 11.6 Reading: 12.4 Done
| الأمر | volts | v | المُخرَج |
|---|---|---|---|
| volts = [12.1, 11.6, 12.4] | [12.1, 11.6, 12.4] | ||
| for v in volts: | 12.1 | ||
| print("Reading:", v) | Reading: 12.1 | ||
| for v in volts: | 11.6 | ||
| print("Reading:", v) | Reading: 11.6 | ||
| for v in volts: | 12.4 | ||
| print("Reading:", v) | Reading: 12.4 | ||
| for v in volts: | |||
| print("Done") | Done |
ظهر السطر for في الجدول أربع مرات لقائمة من ثلاثة عناصر: في المرة الرابعة لم يبق عنصر، فخرجت الحلقة إلى الأمر التالي.
readings = [12.1, 11.6, 12.4, 11.9]
average = sum(readings) / len(readings)
for r in readings:
if r > average:
print(r)12.1 12.4
يبقى البرنامج كما هو لأربع قراءات ولأربعة آلاف قراءة، ولا يتغيّر فيه سوى السطر الأول.
volts = [12, 9, 5]
for v in volts:
v = v * 2
print(volts)
print(v)[12, 9, 5] 10
الحلقة for تعمل أيضا على كل ما يمكن المرور على أجزائه، ومنه الجملة النصية: for ch in "ADC":. وعلى قائمة فارغة لا يُنفَّذ جسمها ولا مرة، ولا يحدث أي خطأ.
items = [4, 7, 2, 9]
s = 0
for x in items:
if x % 2 == 1:
s += x
print(s)6.8 الحلقة for مع range – שילוב של לולאת for עם range
الدالة range تعطي سلسلة أعداد، والحلقة for تمر على السلسلة. عندما نجمع بينهما يصبح لدينا عدّاد جاهز، وهذا أبسط تكرار لعدد معروف من الدورات. وبهذه الطريقة نقرأ أيضا عددا معروفا من القيم، من دون قيمة توقف:
for i in range(4):
print(i, i * 5)0 0 1 5 2 10 3 15
currents = []
for k in range(3):
currents.append(float(input("Current: ")))
print(currents)
print(max(currents))Current: 1.5 Current: 0.75 Current: 2.25 [1.5, 0.75, 2.25] 2.25
الاستعمال الأهم هو المرور على مؤشّرات القائمة: for i in range(len(v)): يعطي 0 ثم 1 حتى آخر مؤشّر، مهما كان طول القائمة. نحتاج إلى ذلك في ثلاث حالات، والحلقة على العناصر لا تكفي في أي منها.
adc = [0, 256, 512, 1023]
for i in range(len(adc)):
adc[i] = round(adc[i] * 5 / 1023, 2)
print(adc)[0.0, 1.25, 2.5, 5.0]
رأينا في البند السابق أن v = v * 2 لا يغيّر القائمة. أما adc[i] = ... فيكتب في خانة القائمة نفسها.
volts = [12, 5, 3.3]
amps = [0.5, 0.2, 0.1]
power = []
for i in range(len(volts)):
power.append(round(volts[i] * amps[i], 2))
print(power)
print("Total:", round(sum(power), 2))[6.0, 1.0, 0.33] Total: 7.33
samples = [0.1, 0.2, 3.2, 3.3, 3.2, 0.2, 0.1]
for i in range(1, len(samples)):
step = samples[i] - samples[i - 1]
if abs(step) > 1:
print("Edge at index", i)Edge at index 2 Edge at index 5
بدأنا من range(1, ...) لأن العنصر الأول ليس قبله جار. ولو بدأنا من 0 لقارنّا العينة الأولى بالعنصر [-1]، أي بالعينة الأخيرة، وهذا خطأ منطقي لا تصدر عنه أي رسالة.
الأمران break وcontinue من الفصل 4 يعملان في for أيضا: عندما نبحث عن أول عنصر يحقق شرطا، نكتب break فور أن نجده، ولا نكمل المرور.
range(len(v) + 1): دورة زائدة تصل بالمؤشّر إلى خارج القائمة. والثاني range(v): نسينا len، فتتلقى range قائمة بدل عدد. وكلاهما يوقف البرنامج.| ما نريده | الحلقة المناسبة |
|---|---|
| نقرأ العناصر فقط، واحدا بعد الآخر | for v in values: |
| نغيّر العناصر، أو نحتاج إلى قائمتين معا، أو إلى عنصر وجاره | for i in range(len(values)): |
| نكرر عددا معروفا من المرات | for k in range(n): |
| لا نعرف كم مرة سنكرر: حتى قيمة توقف أو حتى يتحقّق شرط | while condition: |
a = [2, 5, 1, 8]
t = 0
for i in range(1, len(a)):
if a[i] > a[i - 1]:
t += 1
print(t)
for i in range(0, len(a), 2):
print(a[i])6.9 المعامل in – אופרטור היחס in (in)
التعبير x in values يسأل: هل هذه القيمة عنصر في القائمة؟ ونتيجته قيمة بوليانية، ونقيضه x not in values. عرفنا هذا المعامل مع الجمل النصية، وهو يقارن هنا عنصرا كاملا. في المثال التالي القائمة هي سلسلة E12، أي القيم القياسية للمقاومات. العدد 47 والجملة النصية "47" ليسا القيمة نفسها، ولذلك جاء السطر الأخير False.
e12 = [10, 12, 15, 18, 22, 27, 33, 39, 47, 56, 68, 82]
print(47 in e12)
print(50 in e12)
print(50 not in e12)
print("47" in e12)True False True False
in لها دوران: في for v in values: هي جزء من الحلقة، وفي if v in values: هي سؤال جوابه True أو False.codes = ["R1", "C4", "R1", "D2", "C4"]
unique = []
for code in codes:
if code not in unique:
unique.append(code)
print(unique)['R1', 'C4', 'D2']
نضيف القطعة إلى القائمة الجديدة فقط إذا لم تكن فيها بعد. هذا النمط يتكرر كثيرا.
in عن جزء منها، أما مع القائمة فيبحث عن عنصر مساو تماما: "V" in ["12V"] يعطي False. وهو يقارن بالمساواة التامة، ولذلك لا يصلح للأعداد العشرية المحسوبة، كما تعلمنا في البند 3.3: 0.3 in [0.1 + 0.2] يعطي False.a = [1, 3, 5]
b = [3, 4, 5, 6]
for x in b:
if x in a:
print(x)
print(2 in a or 4 in b)
print([3] in a)6.10 عمليّات الفئة list – עבודה עם פעולות של המחלקה
القائمة كائن من الفئة list، ولهذه الفئة عمليّات جاهزة نستدعيها بنقطة بعد اسم القائمة، كما استدعينا عمليّات الجملة النصية في الفصل 5. والفرق المهم عن الجملة النصية أن هذه العمليّات تغيّر القائمة نفسها، ولا تعطي قائمة جديدة.
| الأمر | عمله |
|---|---|
| a.append(x) | يضيف العنصر x إلى النهاية |
| a.insert(i, x) | يدخل العنصر x في المؤشّر i، ويزيح ما بعده |
| a.extend(b) | يضيف كل عناصر b إلى النهاية |
| a.remove(x) | يحذف أول عنصر يساوي x |
| a.count(x) | يعطي عدد مرات ظهور x، ولا يغيّر القائمة |
| a.sort() | يفرز القائمة تصاعديا في مكانها |
| a.clear() | يفرغ القائمة |
parts = ["R1", "C4", "D2", "C4"]
parts.append("LED")
print(parts)
parts.remove("C4")
print(parts)
print(parts.count("C4"))
parts.insert(1, "Q1")
print(parts)
parts.extend(["U1", "U2"])
print(parts)
parts.clear()
print(parts)['R1', 'C4', 'D2', 'C4', 'LED'] ['R1', 'D2', 'C4', 'LED'] 1 ['R1', 'Q1', 'D2', 'C4', 'LED'] ['R1', 'Q1', 'D2', 'C4', 'LED', 'U1', 'U2'] []
حذفت remove أول ظهور فقط للقطعة C4، ولذلك بقي واحد، وهذا ما أكدته count. والعمليّة append تضيف عنصرا واحدا حتى لو كان قائمة، أما extend فتضيف عناصر القائمة واحدا واحدا.
العمليّة sort – הפעולה sort:
العمليّة sort تفرز الأعداد حسب قيمتها، والجمل النصية حسب الترتيب المعجمي (סדר מילוני)، أي حرفا بعد حرف كما في القاموس. وإذا كتبنا reverse=True كان الفرز تنازليا:
r = [470, 10, 220, 1000, 47] r.sort() print(r) r.sort(reverse=True) print(r) names = ["diode", "LED", "resistor", "Capacitor"] names.sort() print(names) codes = ["100", "47", "9"] codes.sort() print(codes)
[10, 47, 220, 470, 1000] [1000, 470, 220, 47, 10] ['Capacitor', 'LED', 'diode', 'resistor'] ['100', '47', '9']
المقارنة بين الحروف تتم حسب رقم كل حرف في جدول الترميز، الذي تعطيه ord من الفصل 2. وفيه تسبق الحروف الكبيرة جميع الحروف الصغيرة، ولذلك جاءت LED قبل diode. والأرقام في جملة نصية هي حروف أيضا، ولذلك جاءت الجملة "100" قبل الجملة "9"، مع أن العدد 100 أكبر من 9.
sort تفرز في مكانها ولا تعطي قيمة: ما تعيده هو None، أي «لا شيء». إذا كتبنا r = r.sort() فقدنا القائمة، وكذلك مع append. نكتب الأمر وحده في سطر:r = [470, 10, 220] r = r.sort() print(r) print(r[0])
None TypeError: 'NoneType' object is not subscriptable
samples = [2.5, 2.6, 9.9, 2.4, 2.5]
ordered = samples[:]
ordered.sort()
print(ordered)
print("Median:", ordered[len(ordered) // 2])
print("Average:", round(sum(samples) / len(samples), 2))[2.4, 2.5, 2.5, 2.6, 9.9] Median: 2.5 Average: 3.98
هذا ما يفعله مرشّح القيمة الوسطى في معالجة الإشارات. ولو كتبنا ordered = samples لفرزنا القائمة الأصلية أيضا، كما رأينا في البند 6.4.
العمليّة remove – הפעולה remove:
parts = ["R1", "C4"]
parts.remove("D2")ValueError: list.remove(x): x not in list
لذلك نفحص بالمعامل in قبل الحذف. ولحذف كل الظهورات نكرر الفحص بالحلقة while:
parts = ["R1", "C4", "R1", "D2", "R1"]
name = "Q7"
if name in parts:
parts.remove(name)
else:
print(name, "not found")
while "R1" in parts:
parts.remove("R1")
print(parts)Q7 not found ['C4', 'D2']
samples = [5, 0, 0, 7, 0, 3]
for s in samples:
if s == 0:
samples.remove(s)
print(samples)[5, 7, 0, 3]
الحل الأوضح هو أن نبني قائمة جديدة بالعناصر التي نريد أن نبقيها. وحل آخر أن نمر على نسخة ونحذف من الأصلية: for s in samples[:]:.
samples = [5, 0, 0, 7, 0, 3]
clean = []
for s in samples:
if s != 0:
clean.append(s)
print(clean)[5, 7, 3]
a = [8, 2, 6] a.insert(0, 2) a.append(4) a.remove(2) print(a) a.sort() print(a) print(a.count(2)) a.extend([1, 1]) print(len(a))
6.11 قائمة من قوائم – רשימה של רשימות
عنصر القائمة قد يكون قائمة أيضا. القائمة من قوائم (רשימה של רשימות) هي الطريقة الطبيعية لتمثيل جدول: كل قائمة داخلية سطر، والمؤشّر الأول يختار السطر، والثاني يختار العمود.
grid = [[10, 20, 30],
[40, 50, 60]]
print(grid[1])
print(grid[1][2])
print(len(grid), len(grid[0]))
grid[0][1] = 25
print(grid)[40, 50, 60] 60 2 3 [[10, 25, 30], [40, 50, 60]]
نقرأ grid[1][2] من اليسار إلى اليمين: grid[1] هو قائمة، ثم نأخذ منها العنصر [2]. وlen(grid) هو عدد الأسطر، وlen(grid[0]) هو عدد الأعمدة. ونكتب الجدول في البرنامج على عدة أسطر كي يشبه شكله الحقيقي، وبايثون تسمح بذلك داخل الأقواس.
للمرور على الجدول نكتب حلقة داخل حلقة. الحلقة الخارجية تمر على الأسطر، والداخلية على عناصر السطر الواحد، والأمر print() بعد الداخلية ينقلنا إلى سطر جديد:
grid = [[5, 1, 0],
[2, 8, 4]]
for r in range(len(grid)):
for c in range(len(grid[r])):
print(grid[r][c], end=" ")
print()5 1 0 2 8 4
lab = [[78, 85, 90],
[60, 72, 64],
[95, 88, 91]]
for row in lab:
print(row, round(sum(row) / len(row), 1))
for c in range(len(lab[0])):
total = 0
for r in range(len(lab)):
total += lab[r][c]
print("Experiment", c, round(total / len(lab), 1))[78, 85, 90] 84.3 [60, 72, 64] 65.3 [95, 88, 91] 91.3 Experiment 0 77.7 Experiment 1 81.7 Experiment 2 81.7
متوسط السطر سهل، فالسطر قائمة جاهزة نعطيها إلى sum، ونمر عليه مباشرة بلا مؤشّرات. أما متوسط العمود فيحتاج إلى حلقتين، لأن عناصر العمود موزعة على الأسطر. لذلك تكون الحلقة الخارجية هنا على الأعمدة، والداخلية على الأسطر.
نبني جدولا بالطريقة نفسها: قائمة خارجية فارغة، وفي كل دورة نبني سطرا ونضيفه إليها:
rows = 2
cols = 3
grid = []
for r in range(rows):
row = []
for c in range(cols):
row.append(r * 10 + c)
grid.append(row)
print(grid)[[0, 1, 2], [10, 11, 12]]
[[0] * 3] * 2 لا تنشئ سطرين، بل تكرر اسم السطر نفسه مرتين. نغيّر خانة واحدة فتتغيّر في «السطرين»:grid = [[0] * 3] * 2 grid[0][0] = 7 print(grid)
[[7, 0, 0], [7, 0, 0]]
m = [[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]
print(m[2][0], m[0][2])
d = 0
for i in range(len(m)):
d += m[i][i]
print(d)
print(m[1][1:])6.12 كتابة خوارزميات – כתיבת אלגוריתמים (שאינם מובנים בשפה)
الدوال max وmin والعمليّة sort تفعل كثيرا مما سنكتبه هنا. فلماذا نكتبه بأنفسنا؟ لأن هذه الخوارزميات هي أساس التفكير البرمجي، ولأن امتحان البجروت يطلبها، ولأننا كثيرا ما نحتاج إلى تعديل صغير لا توفره الأدوات الجاهزة، مثل مكان العنصر الأكبر لا قيمته فقط.
(أ) أكبر عنصر – מציאת האיבר הגדול ביותר:
الفكرة التي عرفناها في الفصل 4 هي القيمة القصوى (ערך קיצון): نفترض أن العنصر الأول هو الأكبر، ثم نمر على الباقي، وكل عنصر أكبر مما وجدنا يأخذ مكانه.
وكثيرا ما نحتاج إلى مكان العنصر لا إلى قيمته فقط، مثل رقم القناة ذات الجهد الأعلى. عندها نحفظ مؤشّره، وقيمته موجودة في القائمة:
volts = [12.1, 11.6, 12.9, 11.9]
pos = 0
for i in range(1, len(volts)):
if volts[i] > volts[pos]:
pos = i
print("Highest:", volts[pos], "at index", pos)Highest: 12.9 at index 2
temps = [-4, -9, -2]
top = 0
for t in temps:
if t > top:
top = t
print(top)0
الخوارزمية نفسها تعمل على الجمل النصية، فالمعاملان < و> يقارنان بينها حسب الترتيب المعجمي:
print("diode" < "resistor")
print("diode" < "diodes")
print("Zener" < "diode")
print("100" < "9")
print(100 < 9)True True True True False
(ب) أصغر عنصر – מציאת האיבר הקטן ביותר:
نقلب اتجاه المقارنة فقط: < بدل >. وعندما يتكرر الأصغر تبقى المقارنة < على الظهور الأول، ولو كتبنا <= لوصلنا إلى الأخير.
parts = ["resistor", "diode", "capacitor", "zener"]
first = parts[0]
last = parts[0]
for name in parts:
if name < first:
first = name
if name > last:
last = name
print(first)
print(last)capacitor zener
(ج) دمج قائمتين – מיזוג שני מבני נתונים:
الدمج (מיזוג) يعني أن نبني من قائمتين مفروزتين قائمة واحدة مفروزة. مثال ذلك سجلان لأحداث من جهازين، وكل سجل مرتب حسب الزمن. نمسك بمؤشّر في كل قائمة، ونقارن بين العنصرين اللذين يشيران إليهما. الأصغر ينتقل إلى الناتج، ويتقدم مؤشّره خطوة.
a = [3, 8, 15]
b = [1, 9, 11, 20]
merged = []
i = 0
j = 0
while i < len(a) and j < len(b):
if a[i] <= b[j]:
merged.append(a[i])
i += 1
else:
merged.append(b[j])
j += 1
merged += a[i:]
merged += b[j:]
print(merged)[1, 3, 8, 9, 11, 15, 20]
الحلقة تنتهي عندما تنفد إحدى القائمتين. ما بقي في الأخرى أكبر من كل ما مضى، ولذلك يُضاف كما هو. أحد القصّين a[i:] وb[j:] يكون فارغا حتما، فلا حاجة إلى فحص أيهما.
c = a + b ثم c.sort()، ونحصل على النتيجة نفسها. لكن الدمج يمر على كل عنصر مرة واحدة، فهو أكثر نجاعة (יעילות) عندما تكون القائمتان مفروزتين.(د-1) الفرز الفقاعي – מיון בועות:
الفكرة في الفرز الفقاعي (מיון בועות) بسيطة: نقارن كل عنصر بجاره، وإذا كانا بالترتيب الخاطئ نبدّل بينهما. بعد مرور واحد على القائمة يكون العنصر الأكبر قد وصل إلى نهايتها، كفقاعة تصعد إلى السطح. نتابع أولا مرورا واحدا:
وهذا المرور في برنامج، على قائمة أقصر. التبديل بسطر واحد كما تعلمنا في البند 2.6، لأن الجهة اليمنى تُحسب كلها قبل الإسناد:
nums = [7, 3, 9, 1]
for j in range(3):
if nums[j] > nums[j + 1]:
nums[j], nums[j + 1] = nums[j + 1], nums[j]
print(nums)| الأمر | nums | j | nums[j] > nums[j + 1] | المُخرَج |
|---|---|---|---|---|
| nums = [7, 3, 9, 1] | [7, 3, 9, 1] | |||
| for j in range(3): | 0 | |||
| if nums[j] > nums[j + 1]: | True | |||
| nums[j], nums[j + 1] = nums[j + 1], nums[j] | [3, 7, 9, 1] | |||
| for j in range(3): | 1 | |||
| if nums[j] > nums[j + 1]: | False | |||
| for j in range(3): | 2 | |||
| if nums[j] > nums[j + 1]: | True | |||
| nums[j], nums[j + 1] = nums[j + 1], nums[j] | [3, 7, 1, 9] | |||
| for j in range(3): | ||||
| print(nums) | [3, 7, 1, 9] |
العنصر الأكبر وصل إلى مكانه، لكن الباقي لم يُفرز بعد. لذلك نكرر المرور. في كل مرور جديد يدخل عنصر آخر إلى مكانه في النهاية، فنقصّر المدى بواحد. وقائمة من n عناصر تحتاج إلى n−1 مرور:
nums = [7, 3, 9, 1, 5]
n = len(nums)
for i in range(n - 1):
for j in range(n - 1 - i):
if nums[j] > nums[j + 1]:
nums[j], nums[j + 1] = nums[j + 1], nums[j]
print(nums)[1, 3, 5, 7, 9]
الشرط nums[j] > nums[j + 1] يحدد الاتجاه، ولفرز تنازلي نكتب <. ولأن المعامل > يعمل على الجمل النصية أيضا، فالبرنامج نفسه يفرزها حسب الترتيب المعجمي.
n - 1 - i. إذا كتبنا n فسيصل nums[j + 1] إلى خارج القائمة، لأن كل مقارنة تستعمل المؤشّر j + 1 أيضا.v = [4, 2, 5, 1]
for j in range(3):
if v[j] > v[j + 1]:
v[j], v[j + 1] = v[j + 1], v[j]
print(v)(د-2) فرز التبديل – מיון החלפה:
في فرز التبديل (מיון החלפה) نبني المنطقة المفروزة من البداية: نضع في الخانة الأولى أصغر عنصر. نقارن الخانة بكل خانة بعدها، وكلما وجدنا عنصرا أصغر بدّلنا بينهما. بعد ذلك ننتقل إلى الخانة الثانية، وهكذا.
nums = [7, 3, 9, 1, 5]
n = len(nums)
for i in range(n - 1):
for j in range(i + 1, n):
if nums[j] < nums[i]:
nums[i], nums[j] = nums[j], nums[i]
print(nums)[1, 3, 5, 7, 9]
الفرق بين الفرزين: في الفقاعي نقارن كل عنصر بجاره ويصل الأكبر إلى النهاية، وفي التبديل نقارن خانة ثابتة بكل ما بعدها ويصل الأصغر إلى البداية. وكلاهما بحلقتين متداخلتين. فكم مقارنة يحتاج إليها الفرز؟ نعدّها:
for n in [5, 10, 100, 1000]:
count = 0
for i in range(n - 1):
for j in range(n - 1 - i):
count += 1
print(n, count)5 10 10 45 100 4950 1000 499500
عشرة أضعاف العناصر تعني نحو مئة ضعف من المقارنات، لأن العدد يساوي n(n−1)/2. لذلك لا تعمل هذه الخوارزميات على ملايين العناصر، والعمليّة sort الجاهزة تستعمل خوارزمية أكثر نجاعة. نكتب الفرز بأنفسنا كي نفهم كيف يعمل، أما في برنامج عادي فنستعمل sort.
6.13 الصفّ الثابت: التهيئة والتحويل والطباعة – אתחול Tuple, הפעולה tuple, הדפסה (tuple)
نكتب عناصره بين قوسين مستديرين. الصفّ الثابت مناسب لقيم تنتمي معا، مثل ساعة القياس وجهده، أو لبيانات لا يجوز أن تتغيّر، مثل إعدادات طرف في متحكّم.
reading = (8, 12.4)
pin = ("A0", "input", 5)
empty = ()
one = (5,)
print(reading, pin)
print(empty, one, len(pin))
print(type(reading))(8, 12.4) ('A0', 'input', 5)
() (5,) 3
<class 'tuple'>الدالة tuple تحوّل إلى صفّ ثابت كما تحوّل list إلى قائمة. والأقواس ليست ضرورية عند الإنشاء: الفاصلة هي التي تصنع الصفّ الثابت. لقد التقينا به سابقا من دون أن نسميه: الدالة divmod في الفصل 2 تعطي صفّا ثابتا، والإسناد v, i = 12, 0.5 يبني واحدا ثم يفككه:
print(tuple([1, 2, 3]))
print(tuple("ADC"))
print(tuple(range(4)))
pair = 12, 0.5
print(pair)
print(divmod(17, 5))(1, 2, 3)
('A', 'D', 'C')
(0, 1, 2, 3)
(12, 0.5)
(3, 2)append أيضا:reading = (8, 12.4) reading[1] = 12.0
TypeError: 'tuple' object does not support item assignment
reading = (8, 12.4) temp = list(reading) temp[1] = 12.0 reading = tuple(temp) print(reading)
(8, 12.0)
(أ)
(5)(ب)
(5,)(ج)
5؟ ونفسّر لماذا تختلف الأولى عن الثانية.6.14 البنية التسلسلية للصفّ الثابت: المؤشّر والقصّ – המבנה הסידורי של Tuple, אינדקס וחיתוך
المؤشّر والقصّ يعملان كما في القائمة تماما، موجبين وسالبين، والقصّ يعطي صفّا ثابتا جديدا. والمؤشّر خارج المجال يوقف البرنامج هنا أيضا. ويمكن أن نفكك الصفّ الثابت إلى متغيّرات في أمر واحد، بشرط أن يساوي عددها عدد عناصره:
rec = (14, 12.6, "OK") print(rec[0], rec[-1]) print(rec[1:]) hour, volts, status = rec print(hour, volts, status)
14 OK (12.6, 'OK') 14 12.6 OK
colors = ("black", "brown", "red", "orange", "yellow",
"green", "blue", "violet", "gray", "white")
first = 4
second = 7
power = 2
print(colors[first], colors[second], colors[power])
print((first * 10 + second) * 10 ** power, "ohm")yellow violet red 4700 ohm
المؤشّر هو الرقم نفسه، ولذلك نترجم من رقم إلى لون بلا شروط.
t = (2, 4, 6, 8, 10) print(t[1], t[-1]) print(t[1:3]) print(t[::2]) a, b = t[:2] print(a + b)
6.15 الحلقة for على الصفّ الثابت – לולאת for העוברת על איברי Tuple
for تعمل هنا كما في القائمة، على العناصر وعلى المؤشّرات. وأقوى ما في الصفّ الثابت أن نضعه داخل قائمة: كل صفّ هو سجل لقراءة واحدة لا تتغيّر، والقائمة هي السجل كله الذي يكبر مع الوقت. نطبع سجل قراءات، ونفكك كل صفّ مباشرة في سطر الحلقة، وهذا أوضح من كتابة المؤشّرات.log = [(8, 12.4), (10, 12.7), (12, 13.1)]
print(log[1], log[1][0])
for hour, volts in log:
print("Hour", hour, ":", volts, "V")(10, 12.7) 10 Hour 8 : 12.4 V Hour 10 : 12.7 V Hour 12 : 13.1 V
log = [(1, 5), (2, 9), (3, 4)]
s = 0
for a, b in log:
if a != 2:
s += b
print(s)6.16 العمليّتان count و index – עבודה עם פעולות המחלקה: count, index
لأن الصفّ الثابت لا يتغيّر، فليس له إلا عمليّتان، وكلتاهما تسأل ولا تغيّر. العمليّة count تعطي عدد مرات ظهور القيمة، والعمليّة index تعطي مؤشّر أول ظهور لها، ويمكن أن نحدد لها من أين تبدأ البحث.
bits = (1, 0, 1, 1, 0, 1) print(bits.count(1)) print(bits.index(0), bits.index(0, 2)) print(bits.count(1) % 2)
4 1 4 0
السطر الأخير يحسب خانة الزوجية (סיבית זוגיות): باقي قسمة عدد الخانات التي قيمتها 1 على 2. سنعود إلى هذه الخانة في الاتصال التسلسلي في الفصل 10. والعمليّة index موجودة في القائمة أيضا، وتعمل بالطريقة نفسها.
index يوقف البرنامج. لذلك نفحص بالمعامل in أولا. نبحث عن خط تغذية بين خطوط اللوحة.rails = (3.3, 5, 12, 5)
wanted = 5
if wanted in rails:
print(rails.index(wanted), rails.count(wanted))
else:
print("No such rail")1 2
days = (0, 2, 2, 5, 2, 0) print(days.count(2)) print(days.index(2)) print(days.index(0, 1))
في الفصل 4 قرأت المحطة سلسلة قياسات، لكنها كانت تنسى كل قراءة بعد الأخرى. الآن تتذكر: كل قياس يصبح صفّا ثابتا (hour, volts) يُحفظ في قائمة السجل. قائمة عدّادات تصنّف القياسات إلى ثلاثة مجالات للجهد: منخفض تحت 11.8 V، وسليم حتى 12.6 V، وعال فوق ذلك. وفي النهاية تبحث المحطة عن ساعة الجهد الأعلى، وتفرز القراءات.
log = []
counts = [0, 0, 0]
hour = int(input("Hour (-1 to stop): "))
while hour != -1:
volts = float(input("Battery V: "))
log.append((hour, volts))
if volts < 11.8:
counts[0] += 1
elif volts <= 12.6:
counts[1] += 1
else:
counts[2] += 1
hour = int(input("Hour (-1 to stop): "))
print(log)
print("Low, OK, High:", counts)Hour (-1 to stop): 8 Battery V: 12.4 Hour (-1 to stop): 12 Battery V: 13.1 Hour (-1 to stop): 18 Battery V: 11.6 Hour (-1 to stop): -1 [(8, 12.4), (12, 13.1), (18, 11.6)] Low, OK, High: [1, 1, 1]
في الجزء الثاني تعمل المحطة على السجل الذي بنته. نضعه هنا مباشرة في البرنامج كي نجرّب هذا الجزء وحده، وفي البرنامج الكامل يأتي مباشرة بعد الحلقة:
log = [(8, 12.4), (12, 13.1), (18, 11.6)]
best = log[0]
readings = []
for rec in log:
readings.append(rec[1])
if rec[1] > best[1]:
best = rec
print("Highest:", best[1], "V at hour", best[0])
readings.sort()
print("Sorted:", readings)Highest: 13.1 V at hour 12 Sorted: [11.6, 12.4, 13.1]
لم نستعمل max هنا، لأننا نريد السجل كله لا القيمة وحدها: الساعة مربوطة بالجهد في الصفّ نفسه. نجرّب بأنفسنا: نضيف إلى البرنامج طباعة الساعات التي كان الجهد فيها منخفضا. وماذا يحدث إذا أدخلنا -1 في أول سؤال؟ ولماذا؟
أهمّ أفكار الفصل:
- بنية المعطيات تحفظ قيما كثيرة تحت اسم واحد، فلا تضيع بعد الحلقة.
- المؤشّر يبدأ من 0، وآخر مؤشّر أقل من الطول بواحد، والمؤشّر السالب يعدّ من النهاية.
- في قائمة العدّادات تصبح القيمة نفسها مؤشّرا إلى عدّادها، فلا نحتاج إلى سلسلة شروط.
- الإسناد
b = aلا ينسخ القائمة، بل يعطيها اسما ثانيا. النسخة تُكتبa[:]. - الحلقة
for v in aتعطي قيمة كل عنصر. لتغيير العناصر نمر على المؤشّرات بالدالةrange(len(a)). - لا نحذف من قائمة ونحن نمر عليها، و
sortلا تعيد قائمة. - نبحث عن القيمة القصوى بدءا من عنصر في القائمة، لا من الصفر.
- القائمة تتغيّر والصفّ الثابت لا يتغيّر. سجل القراءات قائمة، والقراءة الواحدة صفّ ثابت.
ملخّص أوامر الفصل:
| الأمر | عمله |
|---|---|
| a = [1, 2] a = [] a = list(x) | تهيئة قائمة |
| a[i] a[-1] a[i][j] | الوصول إلى عنصر |
| a[start:stop:step] b = a[:] | القصّ والنسخ |
| a + b a += b [0] * n | الوصل والتكرار |
| range(start, stop, step) | سلسلة أعداد صحيحة |
| for v in a: | المرور على العناصر |
| for i in range(len(a)): | المرور على المؤشّرات |
| x in a x not in a | هل القيمة عنصر في القائمة؟ |
| a.append(x) a.insert(i, x) a.extend(b) | إضافة عناصر |
| a.remove(x) a.clear() | حذف عناصر |
| a.count(x) a.sort() | العدّ والفرز |
| t = (1, 2) t = (5,) t = tuple(x) | تهيئة صفّ ثابت |
| t.count(x) t.index(x) | عمليّتا الصفّ الثابت |
قاموس المصطلحات – מילון מונחים:
| بالعربية | بالعبرية (كما تظهر في الامتحان) | English |
|---|---|---|
| بنية المعطيات | מבנה נתונים | Data structure |
| القائمة | רשימה | List |
| العنصر | איבר | Element |
| المؤشّر | אינדקס | Index |
| القصّ | חיתוך | Slicing |
| قائمة عدّادات | רשימת מונים | Counter list |
| قائمة مُجمِّعات | רשימת צוברים | Accumulator list |
| القائمة الفارغة | רשימה ריקה | Empty list |
| قائمة من قوائم | רשימה של רשימות | List of lists |
| قيمة قصوى | ערך קיצון | Extreme value |
| الترتيب المعجمي | סדר מילוני | Lexicographic order |
| الدمج | מיזוג | Merge |
| الفرز الفقاعي | מיון בועות | Bubble sort |
| فرز التبديل | מיון החלפה | Exchange sort |
| القيمة الوسطى | חציון | Median |
| الصفّ الثابت | Tuple | Tuple |
| خانة الزوجية | סיבית זוגיות | Parity bit |
[2, 0, 3, 1][7, 8, 3] , [7, 8, 3] , [1, 2, 9][1, 2, 4, 5] , [1, 2, 3] , [7, 7, 8]0 , 7 , 7 , 162 , 2 , 13 , 5 , True , False[8, 2, 6, 4] , [2, 4, 6, 8] , 1 , 67 3 , 15 , [5, 6][2, 4, 1, 5]. لا: العنصر الأكبر فقط وصل إلى مكانه، ونحتاج إلى مرور آخر على الأقل.<class 'int'> , <class 'tuple'> , <class 'int'>. القوسان وحدهما حسابيان، أما الفاصلة فهي التي تصنع الصفّ الثابت.4 10 , (4, 6) , (2, 6, 10) , 693 , 1 , 5أسئلة للتمرين:
v = [4, 8, 15, 16, 23, 42] print(v[2], v[-2]) print(v[1:3]) print(v[::3]) print(len(v[2:]))
15 23 , [8, 15] , [4, 16] , 4for، ويطبع مجموعها وأكبرها.currents = []
for k in range(4):
currents.append(float(input("Current: ")))
print("Total:", sum(currents))
print("Largest:", max(currents))1.5, 0.5, 2.25, 0.75 يطبع: Total: 5.0 , Largest: 2.25volts = [12, 5, 3]
for i in range(len(volts) + 1):
print(volts[i])
volts = volts.sort()
print(volts[0])sort تعيد None. والبرنامج الصحيح:volts = [12, 5, 3]
for i in range(len(volts)):
print(volts[i])
volts.sort()
print(volts[0])12 , 5 , 3 , 3t = (1, 2, 3). أي الأوامر التالية يوقف البرنامج؟(أ)
print(t[0])(ب)
t[0] = 5(ج)
print(t.count(2))(د)
t.append(4)append.samples = [0.4, 1.2, 1.9, 3.3, 4.8, 1.1, 0.7, 3.9]
counts = [0, 0, 0, 0, 0]
for v in samples:
counts[int(v)] += 1
print(counts)[2, 3, 0, 2, 1]samples = [2, 4, 9, 4, 2, 6]
smooth = []
for i in range(len(samples) - 2):
window = samples[i:i + 3]
smooth.append(round(sum(window) / 3, 2))
print(smooth)[5.0, 5.67, 5.0, 4.0]levels = [2, 7, 3, 4, 9, 1, 5, 2]
for i in range(1, len(levels) - 1):
if levels[i - 1] < levels[i] > levels[i + 1]:
print("Peak at index", i, "level", levels[i])Peak at index 1 level 7 , Peak at index 4 level 9 , Peak at index 6 level 5a = [6, 3, 8]
b = []
for x in a:
if x > 4:
b.append(x - 4)
a[0] = len(b)
print(a, b)| الأمر | a | b | x | x > 4 | المُخرَج |
|---|---|---|---|---|---|
| a = [6, 3, 8] | [6, 3, 8] | ||||
| b = [] | [] | ||||
| for x in a: | 6 | ||||
| if x > 4: | True | ||||
| b.append(x - 4) | [2] | ||||
| for x in a: | 3 | ||||
| if x > 4: | False | ||||
| for x in a: | 8 | ||||
| if x > 4: | True | ||||
| b.append(x - 4) | [2, 4] | ||||
| for x in a: | |||||
| a[0] = len(b) | [2, 3, 8] | ||||
| print(a, b) | [2, 3, 8] [2, 4] |
nums = [3, 8, 2, 9, 4, 7]
n = len(nums)
passes = 0
swapped = True
while swapped:
swapped = False
passes += 1
for j in range(n - 1):
if nums[j] < nums[j + 1]:
nums[j], nums[j + 1] = nums[j + 1], nums[j]
swapped = True
print(nums)
print("Passes:", passes)[9, 8, 7, 4, 3, 2] , Passes: 4data = [[1.2, 1.4, 1.1, 1.3],
[3.0, 3.3, 3.1, 3.2],
[0.5, 4.9, 0.4, 0.6]]
best = 0
top = sum(data[0]) / len(data[0])
for ch in range(len(data)):
average = sum(data[ch]) / len(data[ch])
print("Channel", ch, round(average, 2), max(data[ch]))
if average > top:
top = average
best = ch
print("Highest average: channel", best)Channel 0 1.25 1.4 , Channel 1 3.15 3.3 , Channel 2 1.6 4.9 , Highest average: channel 1bits = (1, 0, 1, 1, 0, 0, 1, 0)
value = 0
for b in bits:
value = value * 2 + b
print(value)
print("Parity bit:", bits.count(1) % 2)178 , Parity bit: 0reg = [1, 0, 0, 1, 1, 0]
k = int(input("Shift: "))
k = k % len(reg)
reg = reg[-k:] + reg[:-k]
print(reg)2 يطبع: [1, 0, 1, 0, 0, 1]שאלות בגרות – أسئلة بجروت للفصل 6
| البند | المطلوب | الإجابة |
|---|---|---|
| (أ) | نقرأ في حلقة رقم الأغنية حتى يُدخَل رقم خارج المجال، ونعدّ الأصوات في قائمة عدّادات. | في الأسفل |
| (ب) | نطبع رقم الأغنية التي نالت أكثر الأصوات، وأي واحدة منها عند التساوي. | في الأسفل |
| (ج) | نحسب متوسط الأصوات، ونطبع أرقام الأغاني التي نالت أقل منه. | في الأسفل |
(أ) الأغاني مرقّمة من 1 إلى 50 والمؤشّرات من 0 إلى 49، ولذلك يقع عدّاد الأغنية في الخانة song - 1. وشرط الحلقة هو المجال نفسه، فأي رقم خارجه ينهيها. (ب) نبحث عن مؤشّر الأكبر كما في البند 6.12، ونطبع المؤشّر زائد 1. (ج) نحسب المتوسط من مجموع الأصوات، ثم نمر على القائمة مرة أخرى. هذا بالضبط ما لا يمكن عمله من دون قائمة.
songs = 50
votes = [0] * songs
song = int(input("Song number: "))
while 1 <= song <= songs:
votes[song - 1] += 1
song = int(input("Song number: "))
best = 0
for i in range(1, songs):
if votes[i] > votes[best]:
best = i
print("Most votes: song", best + 1)
average = sum(votes) / songs
print("Average:", average)
print("Below average:")
for i in range(songs):
if votes[i] < average:
print(i + 1, end=" ")خمسون أغنية تعني مُخرَجا طويلا لا يمكن فحصه بالعين. لذلك نغيّر السطر الأول مؤقتا إلى songs = 5، وندخل 2, 3, 2, 1, 2, 3, 5, 4, 2, 3, 6. الرقم 6 خارج المجال فينهي القراءة. يطبع البرنامج: Most votes: song 2 , Average: 2.0 , Below average: , 1 4 5
وعند التساوي تختار المقارنة > الأغنية الأولى، لأن الثانية ليست أكبر منها، والسؤال يقبل أي واحدة منهما:
| الأمر | i | best | votes[i] > votes[best] | المُخرَج |
|---|---|---|---|---|
| votes = [3, 7, 7, 1] | ||||
| best = 0 | 0 | |||
| for i in range(1, 4): | 1 | |||
| if votes[i] > votes[best]: | True | |||
| best = i | 1 | |||
| for i in range(1, 4): | 2 | |||
| if votes[i] > votes[best]: | False | |||
| for i in range(1, 4): | 3 | |||
| if votes[i] > votes[best]: | False | |||
| for i in range(1, 4): | ||||
| print("Most votes: song", best + 1) | Most votes: song 2 |
| البند | المطلوب | الإجابة |
|---|---|---|
| القراءة | نقرأ في حلقة رقم عامل التوصيل والتقييم والإكرامية، ونتوقف عند رقم غير قانوني. | في الأسفل |
| الإكراميات | نطبع مجموع ما ناله عاملا التوصيل من إكراميات. | في الأسفل |
| الأفضل | نطبع رقم عامل التوصيل صاحب التقييم الأعلى. | في الأسفل |
| العلاوة | نطبع 20% من إكراميات عامل التوصيل الأفضل. | في الأسفل |
لكل عامل توصيل قيمتان تتراكمان، فنبني قائمتي مُجمِّعات متوازيتين، والمؤشّر courier - 1 يدل على العامل نفسه في القائمتين. والشرط courier in [1, 2] يعبّر عن نهاية القراءة بدل شرطين مربوطين بالمعامل or.
tips = [0, 0]
ratings = [0, 0]
courier = int(input("Courier: "))
while courier in [1, 2]:
ratings[courier - 1] += int(input("Rating (1-5): "))
tips[courier - 1] += float(input("Tip: "))
courier = int(input("Courier: "))
print("Total tips:", sum(tips))
if ratings[0] >= ratings[1]:
best = 0
else:
best = 1
print("Best courier:", best + 1)
print("Bonus:", tips[best] * 20 / 100)Courier: 1 Rating (1-5): 5 Tip: 20 Courier: 2 Rating (1-5): 4 Tip: 30 Courier: 1 Rating (1-5): 2 Tip: 10 Courier: 0 Total tips: 60.0 Best courier: 1 Bonus: 6.0