مقدمة في علوم الحاسوب والبرمجة باستخدام Python › المحاضرة 14: القواميس (Dictionaries) 16 / 30 السابق التالي

النص الكامل للمحاضرة 14: القواميس

النص الكامل للمحاضرة 14: القواميس

المصدر الأصلي: النص الرسمي الإنجليزي، PDF، المحاضرة والفيديو الرسمي.

النسبة والترخيص: آنا بيل (Ana Bell)، مقرر 6.100L، خريف 2022، معهد ماساتشوستس للتكنولوجيا، MIT OpenCourseWare. هذه ترجمة وتكييف عربي غير رسمي للاستخدام غير التجاري، وليست معتمدة من MIT ولا تعني تأييده لها؛ تخضع المواد الأصلية المشمولة والترجمة لرخصة CC BY-NC-SA 4.0، مع وجوب نسبة المصدر ومشاركة التكييفات بالرخصة نفسها. لا تشمل الرخصة الافتراضية مواد الأطراف الثالثة المستثناة.

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

صفحة المصدر 1

MITOCW | المحاضرة 14 من 6.100L، النسخة المتعددة.mp4

[شعار صوتي]

آنا بيل (ANA BELL):

حسنًا يا جماعة. لنبدأ. ستكون محاضرة اليوم عن هذا الشيء المسمى القواميس (Dictionaries)، وليست القواميس التي استخدمها آباؤنا وأجدادنا. لاحظوا أنني لم أستخدم فعليًا قواميس الكتب العادية أيضًا، ربما مرة واحدة في حياتي كلها.

بل هي عن قاموس Python فعليًا. سيكون هذا نوع بيانات (Data Type) جديدًا لم نعمل به من قبل. لكنه سيكون نوع بيانات مركبًا (Compound Data Type)، مثلما رأينا القوائم (Lists) والصفوف (Tuples). وسيكون فقط مختلفًا جدًا عن القوائم والصفوف.

قبل أن أقدّم مجموعة من الصيغ وما قاموس Python، لنحاول فقط توضيح الدافع للحاجة إلى هيكل بيانات (Data Structure) كهذا. لنفترض أن لدينا المسألة التالية. تعاملنا مع هذه المسألة في كثير من محاضراتنا. لكننا نريد مرة أخرى تخزين معلومات الطلاب.

لنقل إننا نريد تخزين معلومات الدرجات لمجموعة من الطلاب. بما نعرفه حتى الآن نستطيع تخزين المعلومات باستخدام القوائم. إنه هيكل بيانات معقول جدًا للاستخدام، لأن طلابًا جددًا قد ينضمون إلى الصف. وقد ينسحب طلاب. وقد تتغير درجات، وأشياء من هذا النوع. فلنستخدم هيكل البيانات القابل للتغيير (Mutable) هذا، أي قائمة. لنقل إننا نريد تخزين أسماء الطلاب ودرجاتهم في المقرر، مثل تقديرهم النهائي بالحروف.

إضافة إلى ذلك، نستطيع تخزين أشياء مثل درجات الاختبارات المصغّرة ودرجات مجموعات المسائل. لكن الآن لنفترض أننا نخزّن الأسماء والدرجات النهائية في المقرر فقط. إذا فعلنا هذا باستخدام القوائم، فإن إحدى الطرق المعقولة لتخزين هذه المعلومات هي القول: ستكون لدي قائمة بكل أسماء الطلاب في صفي.

وستكون لدي قائمة بكل درجات هؤلاء الطلاب في الصف. وسأمرّ أساسًا فهرسًا بفهرس، وأضع القاعدة التي تقول إنني عند فهرس محدد أخزّن كل المعلومات المتعلقة بهذا الشخص الواحد. هنا عند الفهرس 0 أخزّن اسم الطالب ودرجته. وعند الفهرس 1 أخزّن اسم ذلك الطالب John ودرجته. وعند الفهرس 2 أخزّن اسم ذلك الطالب ودرجته. وعند الفهرس 3، وهكذا وهكذا.

الآن عليّ أساسًا تذكر أنني عند فهرس محدد أخزّن كل المعلومات المتعلقة بذلك الطالب، صحيح؟ حسنًا، تبدو طريقة معقولة لفعل هذا. لنقل الآن إنني أردت البحث عن درجة طالب محدد. أكتب هذه الدالة المسماة get_grade. تأخذ بعض المعاملات (Parameters).

أول شيء ستأخذه هو اسم الطالب، Ana مثلًا. وسأمرّر قائمة كل الأسماء في صفي وقائمة كل الدرجات في الصف. أي هاتين القائمتين اللتين أنشأتهما سابقًا، صحيح؟ تُمرّران إذًا إلى هذه الدالة. تستطيعون تخيّل أنه إذا كانت لدينا قائمة بكل شخص في MIT، فهذه القوائم التي نمرّرها بوصفها معاملات ستكون كبيرة جدًا.

كيف نحصل فعليًا على التقدير بالحرف المرتبط بطالب؟ سنستخدم حقيقة أن التقدير بالحرف للطالب عند الفهرس i في قائمة الدرجات سيكون الحصول على تقدير الطالب عند الفهرس نفسه في قائمة الأسماء. لذلك علينا معرفة هذا الطالب المحدد الذي يُمرَّر هنا: عند أي فهرس يوجد في قائمة الأسماء؟

صفحة المصدر 2

هذا ما يفعله هذا السطر من الكود. يستخدم دالة index هذه على قائمة الأسماء مع معامل، Ana مثلًا. سيُرجع لنا هذا الفهرس الذي توجد عنده Ana في قائمتي. من المثال السابق سيقول إن — سيُرجع العدد 0، لأن Ana مخزّنة في قائمة الأسماء عند الفهرس 0.

والآن بعدما أصبح ذلك الفهرس في يدي، مخزّنًا في المتغير i، أستطيع الفهرسة داخل قائمة الدرجات عند الفهرس نفسه، حسنًا؟ أستطيع إذًا الحصول على قائمة الدرجات عند الفهرس 0، فتُرجع لي الدرجة التي حصلت عليها في ذلك المقرر بالتحديد، أو أي شيء نخزّنه هنا، حسنًا؟ ثم نُرجع فقط الصف student, grade.

يصبح هذا فوضويًا جدًا، صحيح؟ ذكرت بالفعل أنه إذا كانت لدي قائمة بمجموعة كاملة من الطلاب لصف كبير جدًا أو للجامعة كلها، فإن الاستمرار في تمرير كل هذه القوائم يصبح صعب الإدارة جدًا. إذا كانت لدي إضافة إلى ذلك كل قوائم الاختبارات المصغّرة وكل قوائم مجموعات المسائل التي تخزّن أيضًا معلومات إضافية للطالب، فعليّ بعد ذلك تمريرها إلى دوالها المعنية. فيصبح الأمر فوضويًا جدًا، صحيح؟ كتابة هذه الدوال التي تسترجع المعلومات.

وإضافة إلى ذلك، إذا كنا نغيّر هذه القوائم، مثل دخول طالب جديد وحاجتنا إلى إضافة كل معلوماته، فعليّ التأكد من تحديث كل واحدة من هذه القوائم التي أحتفظ بها. وإذا غادر طالب أو انسحب من المقرر، فعليّ تذكر إزالة ذلك الفهرس من كل هذه القوائم المختلفة. موقف فوضوي جدًا جدًا قد ندخله باستخدام هذه الطريقة لتخزين معلومات الطلاب.

لنجرب أسلوبًا مختلفًا. بدلًا من استخدام كل هذه القوائم المختلفة، لنقل إننا سنخزّن كل شيء في قائمة رئيسية (Master List). لا نخزّن إذًا قوائم كثيرة. سنخزّن قائمة واحدة فقط لدرجات الصف. وطريقة تخزينها وفقًا لهذه الشريحة ستكون قائمة grades هذه. حسنًا، هذه قائمة واحدة تحتوي على ثلاثة عناصر. وتستطيعون تخيّل أنه إذا كان لدينا طلاب أكثر فسنضع كل هؤلاء الطلاب في هذه القائمة الرئيسية فقط.

ما كل واحد من عناصر الطلاب هذه؟ كل عنصر طالب هو نفسه قائمة. لدي بالفعل إذًا قائمتي الرئيسية. وكل عنصر داخل هذه القائمة هو أيضًا قائمة. هذه قائمة لـEric، وقائمة لـAna، وقائمة لـJohn. هذه أسماء متغيرات. ممّ ستتكون هذه القوائم؟ ستتكون من ثلاثة أشياء.

لاحظوا الفاصلتين هنا. أول شيء هو الاسم. والثاني قائمة أخرى تحتوي على درجات مجموعات المسائل. وأستخدم هذا العنصر من تلك القائمة للدلالة على ما تمثله تلك المجموعة من الأعداد. ثم قائمة أخرى بوصفها عنصري الثالث، وهي درجات الاختبارات المصغّرة. ومرة أخرى، أشير بالعنصر الأول من تلك القائمة إلى ما تحتويه هذه القائمة.

حسنًا، لدي قوائم، قائمة رئيسية بها ثلاث قوائم فرعية لطلابي الثلاثة. وكل واحدة من تلك القوائم تحتوي على ثلاثة عناصر: سلسلة نصية (String)، وقائمة، وقائمة أخرى. ثم تتكون هاتان القائمتان نفسهما أيضًا من سلسلة نصية وقائمة. إذًا معقد جدًا. هيكل بيانات — أو نوع من التركيب أو خيار تصميم اتخذته هنا. لكنه يحل مشكلة الاحتفاظ بكل هذه القوائم المختلفة في متغيرات منفصلة.

لنقل الآن إنني أردت كتابة دالة تحصل على درجات طالب محدد، سواء درجات مجموعات المسائل أو الاختبارات المصغّرة. هذه الدالة التي تفعل ذلك. مرة أخرى لا تبدو جميلة جدًا. ما الذي ستأخذه هذه الدالة؟ ستكون who سلسلة نصية تمثل الاسم، Ana مثلًا. وستكون what أيضًا سلسلة نصية تمثل المعلومات التي أريد الحصول عليها، إما ps أو mq. وستكون data قائمتي الرئيسية لكل الدرجات. أي grades تساوي هذه القائمة التي تضم الجميع.

صفحة المصدر 3

ما الذي سيفعله هذا الكود؟ لديه حلقة for هنا في الأسفل وحلقة for متداخلة (Nested) داخلها. حلقة for الخارجية تنظر أساسًا إلى كل واحد من هذه العناصر هنا، وتنظر إلى العنصر عند الفهرس 0، أي Eric أو Ana أو John، وتأخذ فقط القائمة التي يطابق فيها ذلك الجزء، تلك السلسلة هنا، who. فإذا كان الطالب عند الفهرس 0 يساوي who هنا، فقد وجدنا الطالب الذي أريد الحصول على معلوماته. رائع. حصلت الآن، أخذت الجزء الصحيح، القائمة الصحيحة.

والآن أهتم بدرجاته لشيء what محدد، إما mq أو ps. أفعل الشيء نفسه تمامًا مرة أخرى لتلك القائمة هنا، صحيح؟ إذا كنت مهتمة بدرجات ps لـAna، آخذ هذه القوائم هنا. ثم سأتحقق مما إذا كانت — info عند الفهرس 0، أي هذه ps أو هذه mq، تطابق what، إما ps أو mq، لمطابقة ما أهتم بالحصول عليه، المعلومات، المعلومات التي أهتم بالحصول عليها. ثم سأدخل تعليمة if هذه إذا تطابقتا، وأُرجع who وinfo.

مرة أخرى، معقد جدًا. لا حاجة إلى فهم هذا بهذا القدر من الدقة، لأننا لن نستخدم هذه الطريقة طويلًا. get_grades هذه هنا، مثلًا، إذا أخذت درجات اختبارات Eric المصغّرة وشغّلت الكود، ستُرجع لي هذا الصف، الذي يُرجع لي اسم الطالب، ثم هذه القائمة الفرعية فقط للشيء الذي كنت مهتمة به، وفي هذه الحالة الاختبارات المصغّرة.

ويحصل لي على جميع الدرجات. ثم أستطيع الفهرسة في هذا الصف المُرجع لأحصل إما على درجة الاختبار الأول أو الثاني. حسنًا، والأمر نفسه لـAna. في هذه الحالة بالتحديد يحصل لي فقط على الصف الذي فيه اسمي ثم تلك القائمة الفرعية بدرجات مجموعات المسائل.

حسنًا. مرة أخرى، فوضوي جدًا. اتخذت خيار تصميمي لكيفية إنشاء كل هذه القوائم مع قوائم فرعية، وقوائم فرعية داخلها. لذلك سيكون عليّ على الأرجح توثيق ذلك إذا استخدمت هذه الطريقة. ثم هذه الدالة للحصول على المعلومات، مرة أخرى، معقدة جدًا. صعبة القراءة.

إذًا ليست طريقة رائعة حقًا لتخزين المعلومات أيضًا، لكن الفكرة وراء هذا هي محاولة تخزين بعض البيانات المرتبطة بنوع من المفتاح (Key)، صحيح؟ ps أو mq، أو في هذه الحالة أخزّن مجموعة من الدرجات لـEric أو Ana أو John.

نستطيع استكشاف تلك الفكرة. وهذا أساسًا ما ستفعله القواميس لنا. ستسمح لنا بإنشاء هياكل بيانات تربط نوعًا من الفهارس المخصصة (Custom Index)، مفتاحًا، بقيمة. مثلما يفعل قاموس الكتب، يربط كلمة بتعريفها. سنستطيع إنشاء قواميسنا الخاصة التي تربط كائنًا بكائن آخر.

عندما ننشئ قاموسًا، نسمي كل «عنصر»، بين علامتي اقتباس، في القاموس مدخلًا (Entry). وذلك المدخل هو ربط مفتاح بقيمة. لرسم تشابه مع القائمة فقط، نستطيع التفكير في القائمة على أنها تربط شيئًا بشيء آخر. الشيء الذي تربطه القائمة هو هذا الفهرس، الأعداد 0, 1, 2, 3 بهذا الترتيب، صحيح؟ يجب أن يكون لها عنصر عند الفهرس 0، ثم يزيد ذلك الفهرس بمقدار 1 من هناك، حسنًا؟

ولكل واحد من هذه الفهارس أربط ذلك الفهرس بعنصر ما في قائمتي، صحيح؟ هذا أساسًا ما تفعله القائمة. هناك شيء مرتبط بالفهرس 0، وشيء مرتبط بالفهرس 1، وهكذا. إنها مثل قاموس شديد التقييد، صحيح؟

قاموس Python الفعلي يعمل بطريقة مشابهة، إلا أنني الآن لا أضع أي قيود على فهارسي. تصبح فهارسي هنا هذه الفهارس المخصصة المسماة مفتاحًا. فأستطيع الآن ربط قيمة، تقابل العنصر في قائمتي، بذلك المفتاح. يمكن أن يكون لدي عنصر مرتبط بأي كائن.

صفحة المصدر 4

أستخدم إذًا مصطلح «قيمة» (Value) هنا، وفي القاموس يرتبط المفتاح بقيمة. وهذا مدخل واحد في القاموس. سيكون هذا مربكًا قليلًا، لأننا كنا نستخدم مصطلح قيمة للإشارة إلى قيمة كائن ما فقط، صحيح؟ مثل int، المتغير a له قيمة خمسة أو شيء كهذا.

لكنني سأحاول الآن بذل جهد واعٍ، بعدما قدمنا القاموس وقيم القاموس المرتبطة بمفتاح، لأقول كلما تحدثت عن قيمة القاموس «قيمة القاموس» فقط كي لا يكون الأمر مربكًا. لكن ضعوا ذلك في أذهانكم. قد يكون مربكًا قليلًا في البداية، بعدما صرنا نستخدم المصطلحات نفسها لشيئين مختلفين.

سنمرّ — في هذه المحاضرة سنقدّم مجموعة من الصيغ والعمليات على القواميس. وستكون هناك تمارين «جرّب بنفسك» كثيرة، فقط لإعطائكم قليلًا من التدريب على الصيغ، لأن هذه محاضرة ثقيلة بالصيغ نوعًا ما. آمل إذًا أن يساعد ذلك قليلًا. لكن لنرَ أولًا كيفية تخزين البيانات في قاموس Python.

كما ذكرت، يخزّن قاموس Python مداخل. وذلك المدخل زوج مفتاح وقيمة (Key-Value Pair). تربط مفتاحًا واحدًا بقيمته. يمكن أن يكون المفتاح أي كائن غير قابل للتغيير (Immutable)، وسنرى معنى ذلك بعد قليل. والقيمة المرتبطة بذلك المفتاح، أو قيمة Python المرتبطة بذلك المفتاح، يمكن أن تكون أي كائن تريد، حتى قوائم أو قواميس أخرى.

طريقة إنشاء قاموس Python هي استخدام هذين القوسين المعقوفين الافتتاحي والختامي. كانت الصفوف قوسين دائريين افتتاحيًا وختاميًا. وكانت القوائم قوسين مربعين افتتاحيًا وختاميًا. والقواميس قوسان معقوفان افتتاحي وختامي. وينشئ هذا في الذاكرة قاموسًا فارغًا، أي قاموسًا بلا مداخل. فطول ذلك القاموس 0.

لإنشاء قاموس به مدخل واحد، لدينا أيضًا قوسان معقوفان. ونضيف مدخلًا واحدًا داخله. هذا الشيء ثم نقطتان رأسيتان ثم شيء آخر هو مدخل في قاموسي، مدخل واحد. والشيء قبل النقطتين هو المفتاح. والشيء بعدهما هو القيمة المرتبطة بذلك المفتاح. يمكنك التفكير فيه، إذا رسمنا تشابهًا مع القوائم، على أنه يربط الآن عند هذا الفهرس المخصص 4 العنصر 16 الذي نضعه.

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

أنشئ هنا قاموسًا، ومرة أخرى يبدأ قاموسي بقوسين معقوفين افتتاحي وختامي. وفيه أربعة عناصر، آسفة، أربعة مداخل. ويفصل بين كل مدخل وآخر فاصلة. لدي هنا المدخل الأول. يربط المفتاح Ana بقيمة القاموس B. ومدخلي الثاني مفتاح مرتبط بقيمة A. والمدخل الثالث يربط المفتاح John بالقيمة B. والمدخل الأخير يربط المفتاح Katy بالقيمة A. هذا قاموس يربط أساسًا سلاسل نصية بسلاسل نصية أخرى.

تستطيعون رؤية أنني صوّرت هنا القاموس الذي أنشأناه للتو. لدينا هذه الفهارس المخصصة، صحيح؟ نربط أساسًا أسماء بتقديرات بالحروف، حسنًا؟ هل كل شيء واضح حتى الآن؟ هل الفكرة منطقية من الناحية المفاهيمية، أظن؟ حسنًا، رائع.

صفحة المصدر 5

حسنًا. أول ما نريد فعله بعدما أصبح لدينا قاموس مليء بمجموعة من المداخل: كيف نحصل على مدخل؟ كيف نبحث عن قيمة مرتبطة بمفتاح؟ الطريقة التي نفعل بها ذلك شبيهة جدًا بالطريقة التي نبحث بها عن عنصر في قائمة، صحيح؟ المفتاح في القاموس مجرد فهرس مخصص. كيف بحثنا عن عنصر في قائمة؟ إذا أردت العنصر عند الفهرس 3، فسأقول أساسًا L ثم قوسين مربعين و3، أي L[3]. ويحصل لي هذا على القيمة عند ذلك الفهرس.

لدي الآن فهارسي المخصصة، صحيح؟ فهارسي المخصصة هي هذه السلاسل النصية. ستكون الصيغة نفسها تمامًا. لدي هذا الفهرس المخصص الذي أريد البحث عنه. فأقول اسم القاموس، قوس مربع، فهرس مخصص. إذا قلت grades['John']، ستدخل Python إلى قاموسي المسمى grades. ستبحث عن المفتاح John. وستُرجع لي القيمة المرتبطة بذلك المفتاح، B.

يُقيَّم هذا التعبير كله هنا أو يُستبدل بالسلسلة النصية B. مثلما عندما فهرسنا داخل قائمة، L1[3]، استبدلنا عملية الفهرسة كلها بقيمة العنصر عند ذلك الموضع. الأمر مشابه هنا.

إذا حاولت الفهرسة داخل قاموس ولم يكن ذلك المفتاح موجودًا، لاحظوا أن قاموسي لا يحتوي على السلسلة Grace، ستعطيني Python خطأ مفتاح KeyError. إذا شغّلتم كودًا بالقواميس وحصلتم على استثناء KeyError يُطلق في وحدة التحكم (Console)، فستعرفون أنكم تحاولون الفهرسة بمفتاح غير موجود.

قد يكون السؤال: نعم، نستطيع البحث عن قيمة إذا أعطينا مفتاحًا. هل نستطيع فعل الشيء نفسه لكن بالعكس؟ إذا أعطينا مفتاحًا، آسفة، إذا أعطينا قيمة مثل A أو B أو C أو أي شيء، هل نستطيع البحث عن مفتاح مرتبط بتلك القيمة؟ والإجابة لا. سنحتاج إلى كتابة نوع من الحلقات أو نوع من الكود يمرّ على كل عنصر في قاموسي ليتحقق من كل قيمة ويرى ما إذا كان المفتاح المرتبط بتلك القيمة مكافئًا لما أبحث عنه. لذلك لا يوجد تعبير لطيف لتنفيذ تلك العملية العكسية.

والسبب أن القيم في قاموسي يمكن أن تتكرر. فإذا بحثت عن القيمة B، وأردت معرفة ما المفتاح المرتبط بـB، فهناك في الحقيقة اثنان. كيف تعرف Python أنني أريدهما كليهما؟ كيف تعرف أنني أريد واحدًا فقط؟ كيف تعرف أنني ربما أريد قائمة بكل هذه الأشياء؟ لا تعرف، صحيح؟ سيكون عليك كتابة كود يفعل شيئًا لتلك العملية. وسنرى كيفية فعل ذلك لاحقًا.

حسنًا. لنترككم تعملون على تمرين «جرّب بنفسك» هذا. وهو مجرد تمرين في البحث عن قيمة. هذه دالة أريد كتابتها وفقًا للمواصفات. اسمها find_grades. وgrades قاموس يربط أسماء الطلاب بالدرجات، أي سلسلة نصية بسلسلة نصية، تمامًا كما رأينا في الشريحة السابقة. وستكون students قائمة بأسماء الطلاب. في المثال هنا لدي قاموس المدخلات، هذا الشيء الذي رأيناه للتو. ثم قائمة درجات الطلاب عندي، مثلًا، هاتان السلسلتان Matt وKaty.

في مجموعة من هذه الأسئلة، خصوصًا في الاختبار المصغّر وأشياء من هذا النوع، إذا أصبح الأمر مربكًا قليلًا عندما أحاول كتابة المواصفات بتفصيل كبير لتوضيح ما أريده من هذه الدالة، فمن المهم محاولة استخدام المثال لمساعدتكم على معرفة ما نريده، لأننا نكتب المواصفات بمعنى عام. لكن ينبغي أن يجعل المثال ما نريده واضحًا جدًا، كما نأمل.

في هذه الحالة بالتحديد، ما نريد أن تُرجعه الدالة هو قائمة بدرجات الطلاب الذين يُمرَّرون، صحيح؟ نبحث عن Matt. نرى أن درجته C. ونبحث عن Katy. درجتها A، لذلك أريد إرجاع القائمة C, A بالترتيب نفسه الذي مررت به طلابي.

سأعطيكم دقيقتين للعمل على ذلك، ثم نستطيع كتابته معًا. هذا في السطر 94. إنه مجرد تمرين في البحث عن قيم في القاموس.

صفحة المصدر 6

حسنًا. هل لدى أحد بداية لي؟ نعم، تفضل.

طالب (STUDENT):

[غير مسموع]

آنا بيل (ANA BELL):

نعم، Lnew. ما رأيك في ذلك؟ ستكون هذه قائمة نتائجي. نعم.

طالب (STUDENT):

[غير مسموع]

آنا بيل (ANA BELL):

نعم، حلقة for.

طالب (STUDENT):

[غير مسموع]

آنا بيل (ANA BELL):

نعم. إذًا grades[lm] تبحث عن القيمة المرتبطة بطالبي المسمى lm. وربما نستطيع حفظها هكذا: grade تساوي هذا. ثم قلت append؟ نعم، نستطيع تنفيذ Lnew.append للدرجة. أي شيء آخر؟

طالب (STUDENT):

[غير مسموع]

آنا بيل (ANA BELL):

نعم، return. نستطيع إرجاع Lnew. نعم، كود معقول جدًا. يعجبني كثيرًا. باستثناء المحاضرة الأولى، لا أعرف إن كنا كتبنا أي كود لا يتضمن حلقة. لذلك أفضل رهان لكم عند كتابة كود لأي شيء في هذا المقرر هو التفكير: ما الحلقة التي أستطيع تنفيذها؟ لنشغّل الكود، وينبغي أن يُرجع لي C, A. وهو يفعل ذلك.

الآن بعدما نستطيع المرور — ذكرت هذا من قبل، لكن بمجرد أن نمرّ على صفوف وقوائم وأشياء كهذه، هناك شيء سأضيفه، لأغراض التنقيح فقط، وهو قول شيء مثل lm هي، ثم يمكنك قول مثال لما قد تكون عليه، مثل Ana أو Matt أو أي شيء قد تكونه، فقط لتذكير نفسك بأن ذلك الشيء، متغير الحلقة ذاك، سلسلة نصية. فيصبح لديك شيء أقل لتتذكره وأنت تكتب مزيدًا من الكود. لكن هذا جميل جدًا.

حسنًا. القواميس تثبت بالفعل أنها مفيدة جدًا جدًا. نستطيع إنشاء قيم مرتبطة بفهارس مخصصة. وإذا أردنا الحصول على القيمة المرتبطة بذلك الفهرس المخصص، فالأمر حقًا مجرد فهرسة باستخدام مفتاح، باستخدام ذلك المفتاح المحدد، مثلما فعلنا الفهرسة داخل قائمة، حسنًا؟ لا حاجة إلى حلقة، ولا إلى كل ذلك التكرار. إنه سطر واحد فقط يفهرس داخل القائمة.

لنرَ بعض العمليات الإضافية قبل تمرين «جرّب بنفسك» التالي. لدي قائمة الدرجات التي كنا نعمل عليها في الشريحتين الماضيتين. لنقل إننا نريد الآن إضافة طالب جديد ودرجته. الطريقة التي نفعل بها ذلك شبيهة جدًا بالطريقة التي نضيف بها عنصرًا إلى قائمة بعدما صار لدينا فهرس لتلك القائمة، صحيح؟

هنا لاحظوا أنه ليس لدينا في الحقيقة موضع لـGrace. ومع ذلك أريد إضافتها إلى قاموسي. لا بأس. بهذه الصيغة المحددة هنا، grades عند المفتاح Grace، إذا لم تجد Python الاسم Grace في قاموس مفاتيحي، فستضيفها فقط، حسنًا؟ وهذا جميل جدًا، صحيح؟ لا أحتاج إلى التحقق مما إذا كانت موجودة بالفعل. لا توجد حلقات. تقول فقط grades['Grace'] = 'A'. وها هي تضيفها لك.

ماذا لو أردت تغيير مدخل في قاموسي؟ لنقل إنني أريد تغيير درجة Grace إلى C. grades عند الفهرس المخصص Grace تساوي C. ستدخل وتنظر إلى مفاتيحي. عندما لم تكن Grace موجودة، أضافتها Python مع قيمتها. لكنها موجودة بالفعل هناك، فستكتب Python فوق قيمتها فقط.

صفحة المصدر 7

هذا جميل جدًا، وشيء ينبغي الانتباه إليه إذا كانت لديك قيم بالفعل في القاموس. تريد أن تكون حذرًا بشأن ما إذا كنت تريد حقًا الكتابة فوق الأشياء. لكنه سلوك جميل جدًا جدًا. وهو مختلف عن القوائم، صحيح؟ خصوصًا إضافة مدخل إلى القاموس.

يمكنك حذف مداخل، مثلما حذفنا مداخل من قائمة. نستخدم دالة del. وتقول دالة del: أي مدخل تريد حذفه من أي قائمة؟ هنا نقول فقط اسم قاموسنا عند الفهرس Ana. سيزيل هذا تمامًا Ana وقيمتها، والقيمة المرتبطة بـAna، من القاموس.

ما أريد الإشارة إليه هو أن قاموسنا يتغيّر بكل هذه الطرق المختلفة أو كل هذه الدوال المختلفة، صحيح؟ هنا، عندما أضفت Grace، غيّرت قاموسي الأصلي، صحيح؟ لم تنشئ الحركة نسخة من هذا القاموس مع إضافة Grace، وتترك الأصل دون تغيير. دخلت حرفيًا وغيّرت قاموسي الأصلي لإضافة Grace. غيّرت القاموس الأصلي لتغيير درجتها. وغيّرت القاموس الأصلي لإزالة Ana من القاموس، صحيح؟ إذًا كل هذه الدوال تغيّر قاموسي فعليًا.

حسنًا. شيء آخر مفيد جدًا تستطيع فعله بالقواميس هو التحقق مما إذا كان مفتاح موجودًا في قاموسي. نفعل هذا باستخدام العامل in، هذه الكلمة المفتاحية in. رأينا استخدام in للتحقق مما إذا كان عنصر في قائمة، أو سلسلة فرعية أو محرف في سلسلة نصية، أو عنصر ما في صف. ونستطيع أيضًا استخدامها للتحقق مما إذا كان عنصر أو مفتاح في قاموسي.

أريد الإشارة إلى أنها تتحقق من المفاتيح فقط. لا تبحث عن القيم في القاموس. سنرى كيفية التحقق مما إذا كانت قيمة ما في القاموس بعد قليل. لكن الكلمة المفتاحية in تحديدًا تنظر إلى المفاتيح في القاموس فقط.

إذا كان لدي التعبير: السلسلة John موجودة في grades، تنظر Python إلى المفاتيح فقط وتقول: نعم، ها هي. لا يهمني ما القيمة المرتبطة بها. يهمني فقط أنها في مفاتيحي. لذلك سيُقيَّم هذا التعبير كله، 'John' in grades، أي يُستبدل، بـTrue.

Daniel، بالطبع، ليس في مفاتيح قاموسي. فتُرجع False. وB ليست في مفاتيح قاموسي، مع أنها في قيمي. ما تزال تُرجع False لأنها تنظر إلى المفاتيح فقط.

حسنًا. لنترككم تجربون هذا التمرين. الدالة اسمها find_in_L. مرة أخرى نستطيع استخدام المواصفات والمثال لمساعدتنا على معرفة ما نريده من هذه الدالة. ستكون Ld قائمة من القواميس. في المثال هنا عرّفت ثلاثة قواميس، والمعامل الأول هنا، الشيء الممرر بوصفه Ld، هو القائمة التي عناصرها D1, D2, D3. وk عدد صحيح فقط.

ما أريد فعله هو إرجاع True من الدالة إذا كانت k مفتاحًا في أي من هذه القواميس، وFalse خلاف ذلك. بمجرد أن أرى مفتاحًا يطابق k، أريد إرجاع True. في هذا المثال هنا، عندما أبحث عن k التي هي 2 داخل هذه القواميس، لا تحتوي D1 عليها، لكن D2 تحتوي عليها. فسأُرجع True. وعندما أبحث عن 25 في قائمة القواميس نفسها، تكون 25 قيمة في واحد منها، في D3، لكنها ليست مفتاحًا في D1 أو D2 أو D3. لذلك ستُرجع هذه False.

حسنًا. هذا أدنى قليلًا، في السطر 115. سأعطيكم لحظات، ثم نستطيع كتابته معًا كالمعتاد.

حسنًا. هل يريد أحد أن يبدأ لي هنا؟ كيف نستطيع فعل هذا؟

ملاحظة المترجم: del تعليمة في Python وليست دالة. تستخدم المتحدثة أيضًا «قائمة» شفهيًا في مواضع تقصد فيها القاموس؛ نُقل الشرح كما ورد دون تغيير صامت.

صفحة المصدر 8

طالب (STUDENT):

ننشئ حلقة.

آنا بيل (ANA BELL):

ننشئ حلقة، نعم. For؟

طالب (STUDENT):

[غير مسموع] for d in Ld.

آنا بيل (ANA BELL):

نعم. حسنًا. يعني ذلك أن D هي — أستطيع القول مثلًا K1 مرتبطة بـv1 أو شيء كهذا، صحيح؟ مفتاح إلى قيمة. If k in D؟ نعم، سيتحقق هذا لي من مفاتيحي في ذلك القاموس المحدد الذي أنظر إليه الآن. نعم، نستطيع إرجاع True فورًا، صحيح؟ بمجرد أن نجده، لا حاجة إلى التحقق من القواميس الأخرى. نخرج من الدالة ونُرجع True فقط.

طالب (STUDENT):

[غير مسموع]

آنا بيل (ANA BELL):

الأمر نفسه داخل if أم داخل for أم خارج for؟

طالب (STUDENT):

خارج for.

آنا بيل (ANA BELL):

خارج for نستطيع إرجاع False. نعم. يعجبني هذا الكود كثيرًا. يستخدم العامل in لأداء المهمة. تعمل return False خارج حلقة for جيدًا جدًا، لأنني إذا مررت على كل D داخل Ld هنا، فأنا أتحقق من كل قاموس، صحيح؟

بمجرد أن أجد واحدًا يحتوي على ذلك المفتاح، تعمل return True هذه مثل break وreturn، صحيح؟ تخرج من الحلقة وتُرجع فورًا. ولا تُرجع False. لكن إذا مررت على كل قاموس ولم أجد المفتاح المطابق لـk، عندئذ أُرجع False. نعم.

هل جرب أحد ذلك بطريقة مختلفة، أم هذا — نستطيع بالتأكيد تجربته بعلم منطقي (Boolean Flag)، صحيح؟ نستطيع الإشارة إلى حقيقة أننا وجدناه عبر حلقة ما، وتتبع ذلك، وفي النهاية إرجاع ذلك العلم فقط. هذه طريقة أخرى لفعل ذلك. لكن هذه على الأرجح أكثر الطرق انسجامًا مع Python (Pythonic).

نستطيع تشغيله على هذين المثالين هنا، صحيح؟ أبحث عن 2 لأُرجع True، وعن 25 لأُرجع False. وهو يفعل ذلك. أسئلة عن هذا الكود أو القواميس حتى الآن؟ هل كل شيء واضح حتى الآن؟ حسنًا.

حسنًا. عمليتان أخريان. حتى الآن بحثنا عن قيم في قاموس. وأضفنا أشياء إلى القاموس. وحذفنا أشياء منه. ومن الأشياء المفيدة جدًا القدرة على النظر إلى كل مدخل في قاموسي. السبب في رغبتنا في فعل ذلك هو أننا ينبغي أن نفترض أنه عندما ننشئ قواميسنا لا يكون لها ترتيب، صحيح؟ وهذا مختلف جدًا عن القوائم. القوائم لها ترتيب. كنا نعرف أن العنصر الأول في قائمتنا عند الفهرس 0. والتالي عند الفهرس 1، وهكذا، صحيح؟

كانت القوائم تسلسلات مرتبة من العناصر. لكن القواميس ليست تسلسلات مرتبة من العناصر. هذا ليس صحيحًا تمامًا. حتى إصدار حديث جدًا من Python لم يكن هناك ترتيب مضمون. كانت توضع بترتيب ما لم أستطع معرفة كيفية تحديده.

لكنني نسيت أي إصدار من Python، ربما 3.6 أو شيء كهذا، بدأ يضمن ترتيبًا لعناصر القاموس. وكان ذلك الترتيب هو ترتيب إدراج العناصر نفسه، حسنًا؟

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

ملاحظة المترجم: الحفاظ على ترتيب الإدراج ضمان في لغة Python منذ الإصدار 3.7؛ وكان في CPython 3.6 تفصيلًا في التنفيذ. التردد بشأن رقم الإصدار في الكلام من المصدر.

صفحة المصدر 9

من أول الأشياء التي قد تريد فعلها المرور على جميع المفاتيح في القاموس. لذلك نستخدم دالة اسمها grades.keys. ودالة grades.keys هذه لا تغيّر القاموس إطلاقًا. بل تُرجع لي كائنًا قابلًا للتكرار (Iterable)، تسلسلًا من القيم، هي كل المفاتيح في قاموسي.

نوع بيانات هذه القيمة المُرجعة اسمه dict_keys. ليس نوع بيانات عملنا به من قبل، حسنًا؟ يبدو غريبًا جدًا. لكن إذا أردت، وليس عليك فعل هذا، تستطيع دائمًا تحويل تسلسل القيم هذا، الذي نوعه dict_keys، إلى قائمة، هكذا. إذا حوّلت grades.keys إلى قائمة، فإنه يعطينا هذه القائمة الأكثر ألفة، بحيث يكون كل مفتاح عنصرًا فيها. ليس عليك فعل هذا. لكن إن جعل الأمر أسهل لك فتستطيع، حسنًا؟

هذا السطر من الكود هنا، grades.keys، يُرجع لك — تستطيع التفكير فيه على أنه هذا الكائن القابل للتكرار، هذه القائمة بكل مفاتيح القاموس. مرة أخرى، ليست مرتبة، صحيح؟ هي مرتبة بحسب ترتيب إضافتي لها إلى القاموس، صحيح؟ Ana، ثم Matt، ثم John، ثم Katy. لكنها ليست مرتبة أبجديًا. وإذا كانت لديك أعداد صحيحة، فلن تكون مرتبة تصاعديًا أو تنازليًا. لذلك من الأفضل عدم افتراض ترتيب أصلًا.

بالمثل، نستطيع الحصول على كائن قابل للتكرار يضم كل القيم في القاموس. ولفعل ذلك، كما تتوقعون، نستخدم grades.values. وهذه أيضًا دالة لا تغيّر grades إطلاقًا. بل تُستبدل بنوع بيانات dict_values هذا. لم أره من قبل أيضًا. وتستطيع تحويله إلى قائمة إذا أردت، لأنه أوضح لنا في هذه المرحلة، فيُرجع لنا فقط هذه القائمة بكل قيمة في قاموسي. مرة أخرى، لا ترتيب، صحيح؟ نستطيع رؤية أنه لا يوجد ترتيب باستثناء ترتيب إضافتنا للعناصر فعليًا. نعم.

طالب (STUDENT):

عندما قلتِ إنه يعمل مثل زوج، هل تعنين أنني إذا نفّذت grades تلك في أوقات أخرى ستطبع القائمة نفسها؟

آنا بيل (ANA BELL):

نعم، نعم، ستطبع الكائن القابل للتكرار نفسه، أظن، إذا فعلت ذلك مرة أخرى، نعم.

طالب (STUDENT):

إذا كنا فقط — إذا كنا نمرّ على القاموس فقط، فقد توجد احتمالات أن يظهر [غير مسموع].

آنا بيل (ANA BELL):

إذا كنت تمرّ على القاموس، فليس في إصدار Python الذي نستخدمه. لكن في إصدار سابق، إذا شغّلته على جهازك أو شغّلت الكود نفسه على جهازي، فقد يعطيني ترتيبًا مختلفًا.

لكن في الإصدارات التي نستخدمها من الآن فصاعدًا في Python، لأنكم جميعًا ربما نزّلتم أحدث إصدار من Anaconda وSpyder، فسيضمن ترتيب إدراج العناصر. لكن إذا أخذ شخص يستخدم إصدارًا أقدم من Python كودك وشغّله، فقد يحصل فعليًا على A, A, B, B أو ترتيب آخر لهذه الدوال هنا.

طالب (STUDENT):

[غير مسموع]

آنا بيل (ANA BELL):

نعم، على الرحب والسعة. كون هذه قابلة للتكرار يعني فقط أننا نستطيع أن يكون لدينا شيء مثل for i — إذًا for k in grades.keys تعطينا أساسًا حلقة تكون فيها k كل عنصر في هذه القائمة. فلا بأس بذلك. نستطيع المرور على المفاتيح، أو المرور على القيم مباشرة. لكن ما أجده شخصيًا أكثر فاعلية هو المرور على كل مدخل في القاموس. ليس على المفاتيح أو القيم وحدها فقط، بل على المفاتيح والقيم معًا.

صفحة المصدر 10

لفعل ذلك نستخدم هذه الدالة المسماة grades.items. وكما تتوقعون، ستُرجع أيضًا كائنًا قابلًا للتكرار، حيث ليس كل عنصر في كائني القابل للتكرار المفتاح فقط أو القيمة فقط. بل هو صف من المفتاح ثم فاصلة ثم القيمة، حسنًا؟

ومرة أخرى نستطيع تحويله إلى قائمة ليعطينا شيئًا أكثر ألفة. تستطيعون رؤية أن كل عنصر في القائمة المُرجعة الآن سيكون الصف الذي لدي فيه مدخل، صحيح؟ فمدخلي Ana, B هو هذا العنصر الأول في قائمتي المُرجعة، ثم Matt, A، ثم John, B، ثم Katy, A.

آخذ هذه المداخل معًا، حيث أستطيع الوصول إلى المفتاح والقيمة كليهما لذلك المدخل. وهذا يعني — وهذا هو الجزء المهم — أننا نستطيع فعل شيء كهذا. ونستطيع فعل ذلك للشريحة السابقة أيضًا. لكن لهذا المرور المحدد على grades.items، إذا كنا نأخذ زوج مفتاح وقيمة من items، فهذا يعني أننا نستطيع فعل شيء كهذا. For k, v in grades.items تعني أن Python ستربط k بمفتاح ذلك المدخل، وv بقيمة ذلك المدخل، وأنا أمرّ على كل واحد من هذه الأزواج، صحيح؟

في كل تكرار، أستطيع الوصول إلى المفتاح والقيمة كليهما لذلك المدخل، وهذا مفيد جدًا. إذا كان لدي هذا السطر من الكود هنا، إذا طبعت «المفتاح k له القيمة v»، فستتغير k وv مع كل مدخل، صحيح؟ أنا آخذ المفتاح والقيمة كليهما لذلك المدخل فقط. نعم، سؤال.

طالب (STUDENT):

لاستخدام [غير مسموع] ذلك العنصر، هل هو فعلًا مثل — هل هو فعلًا صف، أم الكائن الفعلي فقط؟

آنا بيل (ANA BELL):

ليس صفًا. نوع الكائن الفعلي هو هذا الشيء dict_items. مرة أخرى، ليس نوعًا عملنا به من قبل. لكنه مجرد النوع، صحيح؟ رأينا قوائم وصفوفًا وقواميس. dict_items نوع بيانات آخر، نعم.

لكن الشيء الرائع أنه قابل للتكرار. فهو تسلسل من القيم، مما يعني أنك تستطيع تحويله إلى قائمة، وهي أيضًا تسلسل من القيم. ويعرف كيف يُجري ذلك التحويل. وتحصل على القائمة الأكثر ألفة التي كنا نستخدمها. أسئلة أخرى؟

حسنًا. أحب فعلًا استخدام grades.items للمرور على المداخل. فلنترككم تجربون هذا التمرين. إنها دالة اسمها count_matches. تأخذ قاموسًا واحدًا d. لم أقل ما العناصر، لكن تستطيع المزج والمطابقة. هنا لدي قاموس يربط int بأعداد int فقط. وهنا لدي قاموس يربط أعدادًا صحيحة وسلاسل نصية وأشياء كهذه. وما أريده من هذه الدالة هو أن تخبرني كم مدخلًا في قاموس المدخلات هذا يطابق فيه المفتاح قيمته.

هنا، في المثال الأول، المفتاح 1. والقيمة 2. فلا يتطابقان. وهذان لا يتطابقان، وهذان لا يتطابقان. لذلك ينبغي أن يكون العدد 0. لكن هنا في الأسفل في هذا المثال، لا تطابق 1 العدد 2، فلا بأس. لكن المفتاح A يطابق قيمته، عدّ واحد. والمفتاح 5 يطابق قيمته، عدّان. إذًا ينبغي أن يُرجع هذا العدد 2. حسنًا، لنترككم تعملون على ذلك قرب السطر 137. ثم سنكتبه معًا.

حسنًا. كيف أستطيع بدء هذا؟ نعم.

طالب (STUDENT):

عدّاد.

آنا بيل (ANA BELL):

عدّاد، نعم.

طالب (STUDENT):

[غير مسموع]

آنا بيل (ANA BELL):

0، نعم.

ملاحظة المترجم: أسماء keys وvalues وitems في الشرح تشير إلى طرق (Methods)، واستدعاؤها في الكود يتطلب الأقواس: grades.keys() وgrades.values() وgrades.items(). لا تضيف هذه الملاحظة محتوى إلى كلام المتحدثة.

صفحة المصدر 11

طالب (STUDENT):

حلقة for؟

آنا بيل (ANA BELL):

حلقة for، نعم.

طالب (STUDENT):

[غير مسموع] v, k in d.items [غير مسموع].

آنا بيل (ANA BELL):

نعم، بوصفها دالة، نعم.

طالب (STUDENT):

إذا كانت v تساوي k؟

آنا بيل (ANA BELL):

v تساوي k. نعم. هنا إذًا تساوي قيمتي مفتاحي لذلك المدخل بالتحديد.

طالب (STUDENT):

Count تساوي count زائد 1.

آنا بيل (ANA BELL):

Count تساوي count زائد 1، ممتاز. نعم، return count. هل فعل أحد ذلك بطريقة مختلفة؟ حسنًا، رائع. نعم.

طالب (STUDENT):

لماذا عليك استدعاؤها مثل [غير مسموع]؟ اضطررت إلى فعلها بطريقة مختلفة [غير مسموع].

آنا بيل (ANA BELL):

نستطيع كتابتها، نعم.

طالب (STUDENT):

نعم. فعلت شيئًا مثل count تساوي 0، ثم نفّذت مثل for x in مثل [غير مسموع] وكان سيستدعي القيمة فقط. و[غير مسموع] مثل عند x تساوي [غير مسموع]. ظننت أنه سيستدعي [غير مسموع] فقط.

آنا بيل (ANA BELL):

نعم. نستطيع القول for x in d.keys أو شيء كهذا، صحيح؟ شيء كهذا، أم لا؟ ونستطيع أيضًا القول for x in d، أظن. قد يعمل ذلك أيضًا لأنه سيأخذ المفتاح لنا. لكن للاحتياط فقط، keys. والآن نحتاج إلى الحصول على القيمة. كيف تحصل على القيمة المرتبطة بالمفتاح x؟

طالب (STUDENT):

مثل المفتاح والأقواس. لا، الأقواس هي —

آنا بيل (ANA BELL):

نعم، قوسان مربعان. إنها فهرسة فقط، صحيح؟ إذًا d ثم قوسان مربعان وx. عفوًا، إذا كانت d[x] تساوي — هذه القيمة تساوي المفتاح، صحيح؟ ثم، مرة أخرى، نزيد count بمقدار 1. هذه طريقتنا الأخرى. نعم.

ليس علينا إذًا استخدام items، لكنها تجعل الأشياء أسهل لأن لدينا في أيدينا متغيرًا هو القيمة ومتغيرًا هو المفتاح. وفعل أشياء مثل الفهرسة يبدأ في أن يكون مربكًا إذا — قد يكون مربكًا. لكن نعم، كلتا الطريقتين صحيحة جدًا. لنشغّله، وينبغي أن يعمل.

العدد الأول 0، كما توقعنا. والعدد الثاني 2. أي أسئلة عن هذا الكود؟ هل هو منطقي؟ هل هناك طريقة أخرى جربها أحد؟ لا؟ حسنًا، جيد.

حسنًا. القواميس كائنات قابلة للتغيير، صحيح؟ لذلك تنطبق كل قواعد الأسماء البديلة (Aliasing) والاستنساخ (Cloning). تذكروا عندما تحدثنا عن القوائم واستخدام علامة التساوي بين قائمة واسم متغير آخر؟ علامة التساوي العادية تعني أنك تنشئ اسمًا بديلًا لتلك القائمة.

ينطبق الشيء نفسه على القواميس. القول D1 = D2، حيث D2 قاموس، يعني أنك أنشأت اسمًا بديلًا لذلك القاموس. فإذا غيّرت القاموس لأي من هذين المتغيرين، فأنت تغيّر الكائن نفسه. إذا أردت فعلًا إنشاء نسخة، تستخدم d.copy، حيث d اسم القاموس الذي تريد نسخه، ويحصل لك ذلك على نسخة من القاموس. ثم تستطيع تغييره دون تغيير الأصل.

ملاحظة المترجم: ترتيب الأسماء المنطوق في اقتراح الطالب هو v, k، مع أن items() تعطي زوجًا بترتيب المفتاح ثم القيمة؛ اختبار المساواة في المثال لا يتأثر بتبديل الاسمين. وd.copy() تنشئ نسخة سطحية، فلا تفصل الكائنات القابلة للتغيير الموجودة داخل القيم عن الأصل.

صفحة المصدر 12

لنتحدث قليلًا عن قيم القاموس والمفاتيح، لأن هناك بعض القيود على مفاتيح القاموس. ولا قيود على القيم. يمكن أن تكون قيم القاموس من أي نوع، صحيح؟ تستطيع أن تكون لديك قيمة قاموس هي عدد عشري float، أو عدد صحيح int، أو سلسلة نصية string، أو صف tuple. ويمكن أن تكون لديك قيمة قاموس هي قائمة، وهي كائن غير قابل للتغيير. ويمكن أن تكون لديك قيمة قاموس هي قاموس آخر. كلها مقبولة، أيًّا كان ما تريد القيم أن تكون عليه.

يمكن أن تكون لديك قيم قاموس مكررة. يمكن أن يكون لديك مفتاح يرتبط بالقيمة 5، ومفتاح آخر يرتبط بالقيمة 5. كله جيد، حسنًا؟ لا تحتاج القيم إلى أن تكون فريدة (Unique). لكن لدينا قيود على المفاتيح، حسنًا؟ أول قيد على المفاتيح أنها يجب أن تكون فريدة، صحيح؟ إذا ربطت مفتاحًا 1 بالقيمة 5، فلا تستطيع ربط مفتاح 1 بالقيمة 6، لأنه إذا ذهبت وبحثت عن القيمة المرتبطة بـ1، فكيف تعرف Python أي قيمة تريد، 5 أم 6، صحيح؟ يجب إذًا أن تكون المفاتيح فريدة أولًا.

ثانيًا، يجب أن تكون المفاتيح غير قابلة للتغيير، أو تقنيًا قابلة للتجزئة (Hashable). لكن لأغراض هذا المقرر فكروا فيها فقط على أنها يجب أن تكون غير قابلة للتغيير. يمكن أن يكون المفتاح واحدًا فقط من هذه الأنواع التي رأيناها حتى الآن: int أو float أو string أو tuple أو bool. لا يمكن أن يكون لديك مفتاح هو قائمة. ولا مفتاح هو قاموس، لأنهما كائنان قابلان للتغيير. لننظر إلى ذلك بمزيد من التفصيل.

السبب في عدم إمكان وجود مفتاح قابل للتغيير هو طريقة تخزين المفاتيح في Python، آسفة، طريقة تخزين القواميس في Python. سأريكم مثالًا في الشريحة التالية. أولًا سأشرح كيفية تخزينها، ثم سنمرّ على مثال يريكم بالضبط لماذا لا يمكن أن يكون لديكم هيكل قابل للتغيير.

طريقة تخزين القواميس في Python هي أنك تحتاج أولًا إلى مفتاح تربطه بقيمة. يبدأ كل شيء بالمفتاح الذي تريد إضافته إلى قاموسك. تشغّل Python أساسًا دالة اسمها دالة التجزئة (Hash Function) على المفتاح.

للتبسيط، لنقل إن المفتاح الذي تحاول تخزينه عدد. ربما تُرجع دالة التجزئة ذلك العدد نفسه، وربما تُرجع شيئًا آخر. إذا حاولت تخزين سلسلة نصية بوصفها مفتاحًا، تشغّل Python أيضًا، ربما، دالة تجزئة مختلفة تأخذ تلك السلسلة التي قد تتكون من مجموعة من المحارف، وتحوّلها إلى عدد ما. دالة التجزئة تأخذ دائمًا مفتاحك وتحوّله إلى عدد، حسنًا؟

فكر في ذلك العدد على أنه يمثل موقعًا في الذاكرة (Memory Location) ستخزّن فيه القيمة المرتبطة بذلك المفتاح. أنت تحصل دائمًا على عدد يمثل موقعًا في الذاكرة. وفي موقع الذاكرة ذاك ستخزّن القيمة. في المرة التالية التي تريد فيها البحث عن القيمة المرتبطة بمفتاح، تشغّل دالة التجزئة نفسها فقط. لن تتغير الدالة. تشغّل دالة التجزئة نفسها على كائنك، وتستطيع الحصول على العدد الصحيح نفسه مرة أخرى. وتستطيع الحصول على القيمة نفسها مرة أخرى.

لكن إذا خزّنت كائنات قابلة للتغيير، فهذا يعني أن ذلك الكائن قد يتغير. فإذا شغّلت دالة التجزئة، الشيء الذي يعطيك عددًا، على شيء تغير، فقد لا يكون ذلك العدد هو نفسه، لأنك غيّرت الشيء الذي تمرّره إلى الدالة. فلماذا ستعطيك القيمة نفسها مرة أخرى؟

لننظر إلى هذا المثال. مرة أخرى نخزّن درجات. ولنقل إننا نحاول تخزين مجموعة من الدرجات داخل ذاكرتنا. ولنقل إن ذاكرتنا عبارة عن 16 موقعًا فقط، من 0 إلى 15. سأخزّن في هذه المواقع درجات مرتبطة بشخص. الدالة التي سأشغّلها على الطالب تستخدم اسمه. سأخزّن درجة Ana في مكان ما. لكنني أحتاج إلى تشغيل دالة تأخذ السلسلة Ana وتحصل لي على عدد. ذلك العدد هو المكان الذي سأخزّن فيه درجتي.

ملاحظة المترجم: تصف المتحدثة القائمة هنا بأنها غير قابلة للتغيير، وهي زلة في النص الرسمي؛ القوائم قابلة للتغيير. كما أن الصف لا يصلح مفتاحًا إلا إذا كانت عناصره قابلة للتجزئة. تمثيل ناتج التجزئة بوصفه موقع ذاكرة مباشرًا تبسيط تعليمي في المصدر، لا وصف كامل لتنفيذ قاموس Python.

صفحة المصدر 13

دالة تجزئة بسيطة قد نستخدمها هي أن نقول: سآخذ A وأربطها بـ1، وB أربطها بـ2، وC بـ3، وهكذا. أستطيع جمع كل تلك الأعداد المرتبطة بالحروف في اسمي: 16. ثم أستطيع أخذ باقي القسمة (Modulo) على 16، وهو عدد المداخل في ذاكرتي. إذا أخذت باقي القسمة على 16، سيعطيني ذلك عددًا من 0 إلى 15، صحيح؟ إذا أخذت الباقي عند القسمة على 16، تحصل على أي عدد من 0 وصولًا إلى 15.

إذا أخذت باقي قسمة اسمي، فهذا يعني أنني سأخزّن درجتي في موقع الذاكرة 0. هل هذا واضح حتى الآن؟ أنشأت أساسًا دالة التجزئة هذه التي تخبرني أين أضع درجتي. الآن أضيف شخصًا آخر. مرة أخرى سأحوّل الحروف في اسمه إلى أعداد حتى أستطيع بسهولة الحصول على عدد من حروفه. فأنا أجزّئ حروفه أساسًا إلى عدد.

مرة أخرى، جمع هذا لـEric يساوي 35. سأأخذ باقي قسمته على 16، مما يعني أنني سأضع درجة Eric في الموقع 3. الشخص التالي John، الشيء نفسه. أجمع الأعداد وآخذ باقي القسمة على 16. سأضع John في الموقع 15. هذه ذاكرتي التي أخزّن فيها القيم المرتبطة بهؤلاء الطلاب.

إذا أردت استرجاع درجتي، أشغّل دالة التجزئة نفسها تمامًا. سأشغّل دالة التجزئة نفسها على اسمي. اسمي لم يتغير، صحيح؟ ما يزال السلسلة النصية. لا يُسمح لي بتغييره لأنه سلسلة نصية. سأحصل إذًا على القيمة نفسها مجددًا، 0. يعني ذلك أنه للحصول على الحرف المرتبط باسمي، أحتاج فقط إلى الذهاب مباشرة إلى موقع ذاكرتي والبحث عن القيمة في موقع الذاكرة ذاك. فأعرف أنها ستكون C.

الآن لنقل إنني أخزّن قائمة، اسم طالب بوصفه قائمة. مرة أخرى، Ana وEric وJohn غير قابلة للتغيير، صحيح؟ لن تتغير. لكن إذا خزّنت Kate بوصفها قائمة، فقد يتغير اسمها. أستطيع أيضًا تشغيل دالة التجزئة نفسها على اسمها. يعني ذلك أن درجتها عندما أخزّنها أول مرة ستكون في الموقع 5. فأنا أخزّن Kate في الموقع 5. هذه السلاسل الثلاث كلها أعرف أنني أستطيع استرجاعها لأنها لا يمكن أن تتغير.

لكن لنقل إن Kate ذهبت وغيّرت اسمها من Kate بحرف K إلى Kate بحرف C. إنه الكائن نفسه، صحيح؟ الشخص نفسه. حصلت على درجتها B في الأصل. إذا أردت استرجاع درجتها، حتى مع تغير اسمها، فما زلت أريد الحصول على B المرتبطة بها بوصفها شخصًا.

لكن Kate بحرف C، إذا شغّلت دالة التجزئة نفسها التي شغّلتها لوضع درجتها في جدولي، تخبرني بأن عليّ الآن البحث عن درجتها في موقع الذاكرة 13، لا في الموقع 5 بعد الآن. إنها ليست هناك. حسنًا، يصبح الأمر مثل: هل اختفى الطالب؟ وكل تلك الأشياء.

هل ترون؟ هذا هو السبب في أنني لا أستطيع جعل كائن قابل للتغيير مفتاحًا لقائمتي، لأنه إذا تغير ذلك الكائن، فقد لا تعطيني دالة التجزئة عند تشغيلها على ذلك الكائن الذي تغير موقع الذاكرة نفسه الذي خزّنت فيه أصلًا القيمة المرتبطة بذلك الكائن. هل هذا منطقي؟

حسنًا. لنعد إلى مثالنا الأصلي، الذي حاولنا فيه تخزين كل شيء في قائمة رئيسية، كل هذه الدرجات في قائمة رئيسية. لنخزّنه الآن في قاموس رئيسي (Master Dictionary). لدي grades. لاحظوا: قوس معقوف ثم قوس معقوف، هذا قاموس. لدي طالبان في صفي، Ana، صحيح؟ هذه معلومات Ana، وBob. هذه معلومات Bob. طالبان فقط في قاموسي الرئيسي.

صفحة المصدر 14

المفتاح Ana سيكون مفتاح مدخل واحد. والمفتاح Bob هو مفتاح المدخل الآخر. وما المعلومات المرتبطة بهذه المفاتيح؟ مع Ana لدي هذا القاموس المرتبط باسمها. إنه هذا الشيء الكبير هنا. سأشرحه بعد قليل، وبالمثل مع Bob. لدى Bob شيء واحد مرتبط به، وهو قاموس آخر. أربط هنا سلاسل نصية بقواميس. ولا بأس بذلك لأن القيم في القاموس يمكن أن تكون قواميس أخرى.

ما هذه القواميس؟ عدد العناصر في القاموس لشخص معين، هناك ثلاثة عناصر، صحيح؟ فاصلة، فاصلة، تفصل بين عناصري الثلاثة. الأول سيرتبط بالمفتاح mq. والثاني يرتبط بالمفتاح ps لمجموعة المسائل، والأخير يرتبط بالسلسلة fin للتقدير النهائي.

إذًا كل واحد من هؤلاء الطلاب لديه هذا القاموس المرتبط به. وذلك القاموس نفسه له ثلاثة مداخل، واحد للاختبار المصغّر، وواحد لـps، وواحد للدرجات النهائية. الآن، ما القيم المرتبطة بتلك المفاتيح؟ الاختبار المصغّر سيكون قائمة. ومجموعة المسائل ستكون قائمة. والنهائي سيكون سلسلة نصية. تمثيل جميل جدًا لصفي، صحيح؟ والأمر نفسه لـBob.

ماذا لو أردنا الآن الحصول على درجة امتحان طالب أو قائمة درجات امتحاناته؟ تذكروا تلك الدالة الكبيرة بحلقتي for المتداخلتين وتعليمات if المتداخلة؟ تصبح هذا السطر. أليس هذا رائعًا؟ تصفيق، يعجبني ذلك. نعم، بالضبط. ينبغي أن نصفّق لهذا، لأن انظروا كم صار سهلًا الآن أن — نعم، شكرًا، نعم.

[تصفيق]

القواميس رائعة يا جماعة. نعم، انظروا، يصبح ذلك السطر هذا — الحصول على درجة اختبار واحدة يصبح هذا السطر الواحد من الكود هنا. لنفككه. مرة أخرى نعمل من اليسار إلى اليمين كلما كانت لدينا هذه السلسلة من الأشياء. أول ما نقوله هو أننا نبحث عن grades عند فهرس ما. تعطيني grades عند فهرس ما ذلك القاموس، شيئًا مثل هذا كله هنا، صحيح؟ حسنًا؟ جيد. هذه الحلقة الأولى من السلسلة.

الآن يُستبدل هذا الصندوق هنا بذلك القاموس. وأُجري فهرسة أخرى داخل ذلك القاموس. يعني ذلك أنني سأحصل على mq المرتبطة بذلك القاموس. القيمة المرتبطة بـmq ستكون هذه القائمة 5, 4, 4. يُستبدل هذا الصندوق هنا إذًا بالقائمة 5, 4, 4. ثم إذا أردت الحصول على قيمة الاختبار الأول فقط، أقول إنني سأفهرس الآن داخل القائمة 5, 4, 4 عند الفهرس 0. فيحصل لي ذلك على 5 فقط. كانت درجة الاختبار الأول لـAna إذًا 5. إنها سيئة جدًا.

حسنًا. لنترككم تفكرون في هذا. هذه دالة، لا يوجد شيء تبرمجونه هنا. التفكير فقط. هذه دالة تحصل على متوسط كل شيء يكون فيه ذلك الشيء هو what في الصف. إذا كانت what هي mq، كما هنا في هذا المثال في الأسفل، إذا كانت what هي mq، فيُفترض أن يحصل هذا الكود على متوسط كل الاختبارات المصغّرة لجميع الطلاب في الصف.

تريد أساسًا الحصول على متوسط 10 زائد 8 زائد 3. وإذا كانت ps، فأريد الحصول على متوسط كل مجموعات المسائل لجميع الطلاب في الصف. أي متوسط 10, 10, 7, 8, 0. لدينا حلقة تمرّ على كل طالب في المفاتيح. الطالب، stud، stud هنا ستكون هذا القاموس، صحيح؟ بالنظر إلى هذا القاموس، ما السطر الذي ينبغي إدراجه هنا بحيث تنشئون قائمة، مجرد قائمة واحدة على المستوى الأعلى، بكل القيم الموجودة هناك؟

صفحة المصدر 15

الشيء الذي تريدون فعليًا أن تنتهوا به، إذا نظرنا إلى درجات ps فقط لأن التفكير بها أسهل قليلًا، سيكون 10, 10, 7, 8, 0. في النهاية، ما أريد الحصول عليه في all_data، هذه القائمة التي أحتفظ بها هنا، هو شيء مثل هذا لـps.

فكّروا في أي واحد من هذه الأسطر سيحقق ذلك. وللمساعدة فقط نستطيع القول إن الطالب هو قاموسي من — من يعتقد أنه الأول؟ الثاني؟ الثالث؟ الرابع؟ لم يعتقد أحد أنه الأول؟ هل أنتم متأكدون؟

حسنًا. لماذا تعتقدون أنه الثاني؟ هل بسبب append؟ نعم؟ لنفكر في ذلك. all_data قائمة، وما الذي نُلحقه؟ ما الذي ستعطينا إياه data عند stud عند what؟ data عند الطالب هي القاموس، هذا القاموس هنا، صحيح؟ هذه القيمة هنا. وإذا أخذنا هذه القيمة وفهرسنا داخل what، فهل ستكون عددًا صحيحًا أم قائمة؟ قائمة.

عندما نُلحق قائمة بقائمة أخرى، ما الذي سيعطينا إياه ذلك؟ إذا كانت لدينا قائمة بالفعل تحتوي على a, b, c، وألحقت بها قائمة أخرى، فهل سيضع العنصر داخل تلك القائمة أم القائمة نفسها؟

طالب (STUDENT):

[غير مسموع]

آنا بيل (ANA BELL):

نعم، بالضبط. لذلك لن يعمل هذا لنا. ومن الواضح أن D ليس صحيحًا أيضًا. وبالتأكيد الفهرسة داخل data عند الطالب عند what لن تكون صحيحة، حسنًا؟ يترك هذا اختيارًا آخر واحدًا. الأول. لنرَ لماذا يعمل الأول.

نحن نصل القوائم (Concatenating)، صحيح؟ علامة الجمع تصلها. لنقل إن لدي بالفعل قائمة a, b, c. سأصل شيئًا لدي بالفعل بـdata عند الطالب عند what، والتي قلنا إنها ماذا؟ هل هي عنصر واحد أم قائمة أخرى؟

طالب (STUDENT):

[غير مسموع]

آنا بيل (ANA BELL):

بالضبط. نصلها إذًا بشيء مثل 10, 10 أو شيء كهذا. سيُرجع لنا هذا a, b, c, 10, 10، مما يسمح لنا بفعل شيء مثل الحصول على مجموع كل هذه العناصر. أسئلة عن ذلك؟ هل هذا منطقي؟ هل هذا واضح؟ نعم.

طالب (STUDENT):

[غير مسموع]

آنا بيل (ANA BELL):

نعم.

طالب (STUDENT):

لماذا [غير مسموع]؟ كيف يُرجع 10 [غير مسموع]؟

آنا بيل (ANA BELL):

لأننا نفهرس داخل mq. إذا فهرست داخل mq، فإن mq مفتاحك. فتأخذ القيمة المرتبطة بذلك المفتاح. ستكون هذه القائمة هنا، 10. أو بالنسبة إلى ps ستكون القائمة 10, 10.

مراجعة سريعة للقوائم والقواميس قبل أن نأخذ مثالًا أخيرًا أطول. مرة أخرى، القوائم تسلسلات مرتبة من العناصر، صحيح؟ هناك عنصر ما عند الفهرس 0. وعنصر ما عند الفهرس 1، وعنصر ما عند الفهرس 2. لدينا إذًا هذه «الفهارس»، بين علامتي اقتباس، صحيح؟ لكن هناك ترتيب لهذه الفهارس، ويجب أن يكون هناك عنصر عند الفهرس 0 ثم صعودًا من هناك، صحيح؟

صفحة المصدر 16

القواميس أيضًا لها هذه «الفهارس»، بين علامتي اقتباس، التي نسميها مفاتيح. لكنها مخصصة. تستطيع أساسًا إعادة ترتيب — تستطيع التفكير في الأمر على أنه مسموح لك بإعادة ترتيب الفهارس كيفما تريد، صحيح؟ لا يوجد ترتيب للفهارس في القاموس. هناك بعض القيود على المفاتيح أو هذه الفهارس، فلا يمكن أن تكون غير قابلة للتغيير أو قابلة للتجزئة. لكن بخلاف ذلك، الأشياء التي تخزّنها المتعلقة بذلك المفتاح يمكن أن تكون من أي نوع، مثلما تستطيع تخزين أي نوع في قائمة.

آخر شيء أريد المرور عليه هو مثال أكبر. وسيعرض مجموعة كاملة من الأشياء التي تحدثنا عنها حتى الآن. سيعرض أولًا كيفية إنشاء القواميس، وهو ما فعلناه اليوم. وسيعرض كيفية إعادة استخدام الدوال، وكيفية كتابة الدوال وإعادة استخدامها في مواضع أخرى. وسيعرض قليلًا من قابلية التغيير أيضًا. لكن هذا كله ضمن مثال أكبر. وإذا مررت على هذا بسرعة قليلًا، فقد أعطيتكم روابط Python Tutor. وهو أيضًا في الملف لتشغّلوه بأنفسكم.

الهدف من هذا المثال الأخير هو أساسًا العثور على أكثر الكلمات شيوعًا في كلمات أغنية. ستكون القواميس مفيدة جدًا لفعل شيء كهذا. سأريكم أولًا ما نريد أن ننتهي به. ثم نستطيع الحديث عن كيفية تقسيم هذه المسألة الأكبر إلى أجزاء أصغر.

حسنًا، هذه هي كل الأجزاء. لكن أساسًا ما أريد أن أنتهي به هو تخزين أغنية بوصفها سلسلة نصية، حسنًا؟ ستتعرفون إلى هذه، لكنها قديمة جدًا. لم أحدّث هذه الأغاني في الحقيقة منذ بضع سنوات. لكن نعم، على أي حال، لا تحكموا عليّ. لدي أغنية مخزّنة بوصفها سلسلة نصية. وسأشغّل كل دالة منفردة. لكن في النهاية ما أريد فعله هو التوصل إلى شيء كهذا.

أريد عرض أكثر الكلمات شيوعًا في الأغنية على المستخدم. لدي هنا قائمة. تستطيعون رؤية أن قوسًا مربعًا افتتاحيًا وختاميًا يخبرانني بأنها قائمة. ولدي عناصر في قائمتي. هذا هو العنصر الأول في قائمتي، الذي يخبر المستخدم بأن الكلمة I تحدث 18 مرة. والعنصر التالي في قائمتي يخبر المستخدم بأن الكلمة we تحدث 17 مرة.

العنصر التالي يخبر المستخدم بأن الكلمات ain't وever وgetting وolder تحدث كلها 16 مرة، ثم وهكذا. ننخفض إذًا في التكرار (Frequency)، حيث تحدث الكلمة الأكثر شيوعًا 18 مرة. ثم أعرض على المستخدم الكلمات الأكثر شيوعًا نزولًا إلى 6 شاملًا. سأختار إذًا قيمة اعتباطية؛ أريد أن أجد في الأغنية الكلمات التي تحدث ست مرات على الأقل مثلًا. حسنًا. هذا هدف البرنامج.

كيف سنحقق هذا؟ من الواضح أنها مهمة كبيرة جدًا. لن أرغب في برمجة الشيء كله مباشرة منذ البداية. لكننا نستطيع تقسيمه فعليًا إلى ثلاثة أجزاء أصغر. الجزء الأول، وسنكتب الكود الخاص به، هو إنشاء ما يسمى قاموس التكرارات (Frequency Dictionary).

بناءً على سلسلة من الكلمات، سننشئ قاموسًا يربط كل كلمة بعدد مرات حدوثها. مصطلح فخم، قاموس التكرارات، لكنه بسيط جدًا. يربط كلمة بعددها داخل سلسلتي الطويلة فقط. يعرض هذا البيانات، وهي هذه السلسلة من الكلمات، بصيغة ألطف بكثير، صحيح؟ إنه قاموس يخبرني بتكرار كل كلمة.

بمجرد أن يصبح هذا في يدي، تصبح الأشياء أسهل قليلًا. أستطيع كتابة دالة أخرى تجد الكلمة التي تحدث أكثر عدد من المرات في ذلك القاموس. الطريقة التي سأفعل بها هذا هي النظر إلى التكرارات في القيم، والعثور على أكبر قيمة بينها، ثم معرفة المفاتيح المرتبطة بتلك القيمة القصوى. وكل هذا ممكن لأنني أعدت تصوّر بياناتي بصيغة قاموس التكرارات هذه.

ملاحظة المترجم: الجملة المنطوقة عن قيود المفاتيح تنفي «غير قابلة للتغيير أو قابلة للتجزئة» في النص الرسمي؛ وهي تناقض الشرح السابق. الشرط التقني الصحيح هو قابلية المفتاح للتجزئة. نُقل النفي كما ورد، مع تمييز هذا التصحيح عن الأصل.

صفحة المصدر 17

الخطوة الأخيرة، بعدما أعرف كيفية كتابة دالة تُرجع لي الكلمات التي تحدث أكثر عدد من المرات، هي العثور على الكلمات التي تحدث عددًا ما من المرات على الأقل. وسأمرّ على مثال لهذه بعد بضع شرائح عندما نصل إليها. لكن هذه الدالة الأخيرة هنا، رقم ثلاثة، يمكنكم فعليًا إعادة كتابتها بطرق كثيرة جدًا. سأريكم طريقة واحدة فقط لكتابتها تتضمن قابلية التغيير. لكن ليس عليكم فعلها باستخدام قابلية التغيير. تستطيعون بالتأكيد فعلها بمجموعة كاملة من — بمجموعة كاملة من التنفيذات الأخرى.

لنبدأ أولًا بإنشاء قاموس يربط الكلمة بتكراراتها. اخترت أغنية حقيقية. وفيها بعض التكرار. وهي قصيرة بحيث تتسع في سطر واحد. لدي هذه الأغنية هنا. ولدي دالتي generate_word_dict. الأغنية سلسلة نصية.

هي أساسًا الأغنية بعد تنظيفها قليلًا، ليس من ناحية الكلمات، بل من ناحية إزالة علامات الترقيم، وإزالة الفواصل، وربما علامات التعجب — أو ربما أبقيت علامات الاقتباس أو شيء كهذا. لكن أساسًا هي إزالة كل علامات الترقيم والأشياء، لأن ذلك سيُفسد عدّ الكلمات عندي.

ما الذي ستفعله هذه الدالة عندما تُعطى سلسلة نصية لأغنيتي؟ أولًا سأحوّل كل حروفي إلى أحرف صغيرة (Lowercase). يعني ذلك أن T-H-E بالأحرف الكبيرة ستُحسب بوصفها الكلمة نفسها مثل t-h-e بالأحرف الصغيرة، وهذه هي الطريقة الصحيحة لفعل ذلك. حوّل كل شيء إلى أحرف صغيرة إذًا.

ثم سأستخدم صديقتنا دالة split، تذكروا، التي تأخذ سلسلتي وتقسّمها عند محرف. افتراضيًا ستقسّمها عند المسافة. يضع هذا سلسلتنا من الكلمات في صيغة سهلة الإدارة جدًا، قائمة من الكلمات. العمل بالقوائم ألطف بكثير من العمل بسلسلة نصية.

بعدما أصبحت لدي قائمة الكلمات، سأنشئ قاموسي الفارغ ثم أملؤه. أمرّ على قائمة الكلمات. ثم لدي خيار. إما أنني رأيت هذه الكلمة بالفعل وأريد تحديث التكرار، صحيح؟ أريد زيادة التكرار بمقدار 1 لأنني أضفت هذه الكلمة بالفعل إلى قاموسي. أو هذه أول مرة أرى فيها هذه الكلمة، وأريد إضافتها إلى قاموسي بتكرار 1.

الحالة الأولى هنا، if، ستحدّث التكرار لأنني رأيت الكلمة بالفعل في قاموسي. أستخدم هنا الكلمة المفتاحية in للتحقق مما إذا كان المفتاح، الكلمة، موجودًا بالفعل في قاموسي. إذا كان كذلك، أزيد تكراره بمقدار 1. وإلا فهذه أول مرة أضيف فيها كلمتي إلى قاموسي. فأعطها تكرار 1. ثم أُرجع قاموس الكلمات. سيربط هذا سلاسل نصية بأعداد صحيحة.

لنعمل عليه في Python Tutor. خطوة، خطوة، خطوة، خطوة، خطوة، حوّلت سلسلة المدخلات إلى أحرف صغيرة، خطوة، قسمتها، فأصبحت لدي الآن هذه القائمة بكل كلماتي، خطوة. هنا نبدأ. أنشأت قاموسي الفارغ هنا. راقبوا هذه المنطقة هنا. ستُملأ قريبًا.

الكلمة الأولى، w، هي rah، صحيح؟ إنها أول كلمة في قائمتي. ومن الواضح أنها أول مرة أراها. ليس لدي شيء في قاموسي الآن. لذلك سأدخل else، وسأضيفها إلى قاموسي بتكرار 1. رائع، عمل ذلك.

الكلمة التالية في قاموسي، في قائمتي، هي هذه، الكلمة نفسها التي رأيتها بالفعل. لذلك سأدخل if وأزيد التكرار إلى 2، حسنًا؟ rah أصبحت الآن 2. التالية هي ah، صحيح؟ هذه كلمتي. لدي التالية في قائمتي. إنها أول مرة أراها. أضفها إلى قاموسي بتكرار 1.

الكلمة التالية التي أراها هي، مرة أخرى. أزيد تكرارها إلى 2. وسأسرع الآن. هذا يزيد التكرار إلى 3 لأنني رأيتها ثلاث مرات الآن. ثم أضيف rom لأول مرة، وmah لأول مرة، وro لأول مرة.

صفحة المصدر 18

وأخيرًا سأزيد تكرار mah مرتين أخريين، لأنها تحدث مرتين أخريين في أغنيتي. زاد إذًا إلى 2، والآن زاد إلى 3. ثم ننتهي. فنُرجع قاموس الكلمات. طريقة جميلة جدًا لتمثيل قائمتي — أغنيتي، صحيح؟ جميلة جدًا.

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

نستطيع القول: لننظر إلى قيمنا ونأخذ أكبر قيمة منها. أستخدم هنا دالة .values هذه على قاموسي لتحصل لي على كل القيم في قاموسي. ستكون هذه القائمة 2, 3, 1, 3, 1. ثم أشغّل دالة max على تلك القائمة. max لقائمة الأعداد هذه تعطيني القيمة القصوى في تلك القائمة، 3.

أصبحت قيمة highest الآن العدد الصحيح 3. وكل ما أحتاج إلى فعله الآن هو المرور على المداخل في قاموسي. هذه k, v في items. وكل ما أتحقق منه الآن داخل هذا التكرار هو ما إذا كانت القيمة تساوي highest.

وأنا أنظر إلى كل مدخل، هل قيمة ذلك المدخل هي نفسها أعلى قيمة رأيتها؟ إن كانت كذلك، فسأحتفظ بقائمة بكل الكلمات التي لها تلك القيمة الأعلى، لأنه قد تكون هناك أكثر من كلمة لها القيمة الأعلى، كما رأينا عندما شغّلناه فعليًا هنا، صحيح؟ كانت لدي هنا قائمة بكل هذه الكلمات التي حدثت 16 مرة. هذا هو المخرج الذي أريد الاحتفاظ به، حسنًا؟

أُلحق إذًا بقائمة words عندي. وفي النهاية أُرجع هذا الصف الذي فيه words ثم فاصلة ثم تلك القيمة الأعلى. إذًا Python Tutor، كما في المرة السابقة. لننشئ قاموسنا الأصلي. هذا ما انتهينا به في المرة الماضية. أعلى قيمة هنا هي 3. وسأمرّ على كل مدخل في قاموسي. تستطيع القول إن k, v ستكون كل واحد من هذه بالترتيب. أولًا هي rah w، ثم ah 3، وهكذا.

من الواضح أن 2 لا تساوي 3، فننتقل. و3 تساوي 3، فنأخذ ah، ونضيفها مباشرة إلى قائمتي هنا. هذه القائمة التي أحتفظ فيها بكل الكلمات التي تحدث بتكرار 3. التالية، لا لـrom، ونعم لـmah، فسأضيفها إلى قائمتي. ثم لا لـro، وانتهيت. ستكون القيمة المُرجعة هذه القائمة — هذا الصف هنا الذي فيه قائمة بالكلمات التي تحدث ثلاث مرات. حسنًا، جيد.

الجزء الأخير، لن أمرّ عليه في Python Tutor. أدرجت رابطًا إليه بالفعل، لأنه يصبح فوضويًا جدًا مع الأسهم. لكنني أشجعكم على محاولة تتبّعه في وقتكم الخاص. سأشرح، مع ذلك، الطريقة التي اخترتها لحل هذه المسألة. اخترت حلها بحيث تتضمن التغيير وإعادة استخدام الدالة التي كتبناها للتو، والتي تحصل لي على القيمة الأعلى والكلمات المرتبطة بقيمة التكرار الأعلى تلك.

هذه هي الفكرة. لدي قاموس الكلمات الأصلي، صحيح؟ هذا قاموس التكرارات الذي أنشأناه منذ البداية. ما سأفعله هو النظر لمعرفة الكلمات التي تحدث بأعلى تكرار. أعلى تكرار، دالتي السابقة، تحصل لي على — تحدد أنه 3. وتحدد أن الكلمات المرتبطة بتلك 3 هي ah وmah. هذا بالضبط ما فعلناه للتو.

ملاحظة المترجم: ورد الزوج الأول في النص الرسمي بصيغة rah w؛ وقد أُبقي كما ورد. العدد المرتبط بـrah في التتبّع نفسه هو 2، كما يتضح من الفقرة التالية ومن قائمة القيم.

صفحة المصدر 19

سآخذ تلك الكلمات وتلك المداخل في القاموس. ثم سأغيّر القاموس لإزالة تلك الكلمات، لأنني أعرف أنها تحدث بأعلى تكرار. أزلت تلك الكلمات الآن، وحفظتها لأنها كانت نتيجة الدالة التي شغّلتها للتو، صحيح؟ أحتفظ إذًا بقائمة التكرار هذه التي ستحتوي على كل الكلمات التي تحدث على الأقل — أظن أنني قلت أكثر من مرة واحدة، أي مرتين على الأقل. سآخذ إذًا الكلمات التي تحدث 3 و2 مرة.

حاليًا أخذت للتو الكلمات التي تحدث 3 مرات. وأزلتها من قاموسي. غيّرت قاموسي فعليًا لإزالة تلك الكلمات. والآن إذا شغّلت الدالة نفسها تمامًا التي كتبتها للتو في الشريحة السابقة على هذا القاموس بعد تغييره، فأي كلمات ستعطيني؟ أي كلمات تحدث أكثر عدد من المرات الآن؟

طالب (STUDENT):

[غير مسموع]

آنا بيل (ANA BELL):

بالضبط، صحيح؟ أعلى قيمة في قاموسي الآن، في قاموس التكرارات هذا، هي 2، لأنني غيّرته لإزالة ما كان سابقًا أعلى قيمة. لذلك أشغّل الدالة نفسها مرة أخرى على القاموس بعد تغييره ليعطيني rah فقط، صحيح؟

آخذ ذلك، وأتتبّعه في قائمة التكرار عندي، صحيح؟ وأغيّر القاموس لإزالته. وأثناء ذلك أتتبّع أيضًا للتأكد من أن أعلى تكرار لدي في القاموس المتبقي هو على الأقل أيًّا كان ما أهتم به. هنا أريده 2 على الأقل. لذلك هذه الدالة، التي سأكتبها، لن تأخذ بعد الآن أي قيم أخرى من القاموس، لأنني لا أريد الآن أخذ التكرار 1. هذه هي القيمة الناتجة.

وهذه هي الفكرة. نستخدم قابلية التغيير والدالة التي كتبناها للتو لأداء هذه المهمة. وهذا هو الكود الذي يفعل ذلك. يشغّل هذا الدالة التي كتبناها سابقًا. تعطينا الخطوة رقم 2 ذلك الصف الذي فيه قائمة بكل الكلمات. تتأكد هذه الحلقة هنا من أنه ما يزال لدي تكرارات قيمتها x على الأقل في القاموس. آخذ الصف الذي أنشأته للتو، شيئًا كهذا، وأضيفه إلى قائمة التكرار عندي. هذه هي القائمة الناتجة التي أتتبّعها. ثم هذا الجزء هنا يزيل الكلمة من قاموسي. فأنا أغيّر القاموس باستخدام الكلمة المفتاحية del التي رأيناها في بداية هذه المحاضرة. نعم، سؤال.

طالب (STUDENT):

الأخرى، أعرف أنها تقول whilst، أساسًا while الـ —

آنا بيل (ANA BELL):

نعم.

طالب (STUDENT):

أظن أنني فقط [غير مسموع] لماذا ما يزال [غير مسموع] الـ [غير مسموع]؟

آنا بيل (ANA BELL):

أظن ربما أن السبب هو أن الدالة — نسيت ما قالته المواصفات، لكنني لا أعرف إن قالت 2 على الأقل أو أكبر من 2، أو x على الأقل أو أكبر من x. يعتمد ذلك على أيهما قلته فعليًا في المواصفات. لكن تستطيعون تخيّل تغيير هذا إلى أكبر من أو أكبر من أو يساوي. ثم نشغّل هذه الدالة مرة أخرى داخل حلقة while هذه للحصول على التكرار [غير مسموع].

نعم. هذه مجرد الملاحظات التي ذكرتها فعلًا في بداية هذا المثال، مجموعة من الأشياء المختلفة التي تعلمناها ونستخدمها داخل هذا المثال. التقطيع (Slicing) أو التقسيم (Splitting)، والمرور على القائمة مباشرة، وقابلية التغيير، واستخدام items، وأشياء من هذا النوع. حسنًا. هذا كل شيء. هذا كل ما لدي. سأراكم يوم الاثنين. الاثنين هو الهالوين (Halloween). إذا أردتم إحضار زي تنكري، فأنا أحب الهالوين. سأرتدي شيئًا مختلفًا عما أرتديه عادة.