<jupyter_start><jupyter_text>מילונים  הקדמה     לפניכם אוספים של נתונים:     בחנות של האדון קשטן יש 2 בננות, 3 תפוחים ו־4 גזרים.    תעודת הזהות של ג'ני היא 086753092, של קווין 133713370, של איינשטיין 071091797 ושל מנחם 111111118.    לקווין מהסעיף הקודם יש צוללות בצבע אדום וכחול. הצוללות של ג'ני מהסעיף הקודם בצבעים שחור וירוק. הצוללת שלי צהובה.    המחיר של פאי בחנות של קשטן היא 3.141 שקלים. המחיר של אווז מחמד בחנות של קשטן הוא 1.187 שקלים.                                          נסו למצוא מאפיינים משותפים לאוספים שהופיעו מעלה.                                    חשוב!            פתרו לפני שתמשיכו!                 ניתן לחלק כל אחד מהאוספים שכתבנו למעלה ל־2 קבוצות ערכים.    הראשונה – הנושאים של האוסף. נניח, הפריט שעבורו אנחנו מחזיקים את המלאי.    השנייה – הפריטים שהם נתון כלשהו לגבי הפריט הראשון: המלאי מאותו פריט, לדוגמה.         חלוקת האוספים ל־2 קבוצות של ערכים.     פריטים מהקבוצה הראשונה לעולם לא יחזרו על עצמם – אין היגיון בכך ש"תפוח ירוק" יופיע פעמיים ברשימת המלאי בחנות, ולא יתכן מצב של שני מספרי תעודת־זהות זהים.     הפריטים מהקבוצה השנייה, לעומת זאת, יכולים לחזור על עצמם – הגיוני שיהיו אותה כמות של בננות ותפוחים בחנות, או שני אנשים בעלי תעודת־זהות שונה שנקראים "משה כהן".     נבחן את המאפיינים המשותפים לעומק בהתייחס לדוגמאות:     המשותף בין האוספים                        אוסף            הערך הקושר (קבוצה ראשונה)            הערך המתאים לו (קבוצה שנייה)            הסבר                                    מוצרים והמלאי שלהם בחנות            המוצר שנמכר בחנות            המלאי מאותו מוצר            יכולים להיות בחנות 5 תפוזים ו־5 תפוחים, אבל אין משמעות לחנות שיש בה 5 תפוחים וגם 3 תפוחים.                            מספרי תעודות הזהות של אנשים            תעודת הזהות            השם של בעל מספר תעודת הזהות            יכולים להיות הרבה אנשים העונים לשם משה לוי, ולכולם יהיו מספרי תעודת־זהות שונים. לא יתכן שמספר מסוים של תעודת זהות יופיע עבור יותר מאדם אחד.                            בעלות על צוללות בצבעים            בעל הצוללות            צבע הצוללות            יכול להיות שגם לקויין וגם לג'ני יש צוללות בצבעים זהים. ג'ני, קווין ואני הם אנשים ספציפיים, שאין יותר מ־1 מהם בעולם (עד שנמציא שיבוטים וכאלו).                            מוצרים ומחיריהם            שם המוצר            מחיר המוצר            לכל מוצר יש מחיר שנקוב עליו. עבור שני מוצרים שונים בחנות יכול להיות מחיר זהה.              מיפוי ערכים     כמו שראינו בדוגמאות, מצב נפוץ במיוחד הוא הצורך לאחסן מיפוי בין ערכים.    נחשוב על המיפוי שקורה בחנות של קשטן, בה הוא סופר את המלאי עבור כל מוצר.    עד היום, היינו מייצגים את המלאי של קשטן באמצעות קוד בצורה הבאה:<jupyter_code>items = ['banana', 'apple', 'carrot']
stock = [2, 3, 4]<jupyter_output><empty_output><jupyter_text>עבור כל תא ברשימת items, שמרנו במקום התואם ברשימת stock את הכמות שנמצאת ממנו בחנות.    יש 4 גזרים, 3 תפוחים ו־2 בננות על המדף בחנות של אדון קשטן.    שליפה של הכמות במלאי עבור אחד המוצרים בחנות תתבצע בצורה הבאה:<jupyter_code>def get_stock(item_name, items, stock):
    item_index = items.index(item_name)
    how_many = stock[item_index]
    return how_many<jupyter_output><empty_output><jupyter_text>בשורה הראשונה מצאנו את מיקום המוצר שאנחנו מחפשים במלאי. נניח, "תפוח" מוחזק במקום 1 ברשימה.    בשורה השנייה הלכו לרשימה השנייה, זו שמאחסנת את המלאי עבור כל מוצר, ומצאנו את המלאי באותו מיקום.    כמות היחידות של מוצר מאוחסנת במספר תא מסוים, התואם למספר התא ברשימה של שמות המוצרים. זו הסיבה שהרעיון עובד.<jupyter_code>print(get_stock('apple', items, stock))<jupyter_output>3<jupyter_text>צורה נוספת למימוש של אותו רעיון תהיה שמירה של זוגות סדורים בתוך רשימה:<jupyter_code>items = [('banana', 2), ('apple', 3), ('carrot', 4)]<jupyter_output><empty_output><jupyter_text>ברשימה הזו הרעיון נראה מובן יותר. בואו נממש דרך להשיג איבר מסוים מתוך הרשימה:<jupyter_code>def get_stock(item_name, items_with_stock):
    for item_to_stock in items_with_stock:
        item = item_to_stock[0]
        stock = item_to_stock[1]
        if item == item_name:
            return stock<jupyter_output><empty_output><jupyter_text>עבור כל tuple ברשימה, בדקנו האם שם הפריט שהוא מכיל תואם לשם הפריט שחיפשנו.    אם כן, החזרנו את הכמות של אותו פריט במלאי.    שימוש בפונקציה הזו נראה ככה:<jupyter_code>get_stock('apple', items)<jupyter_output><empty_output><jupyter_text>שני קטעי הקוד שנתנו כדוגמה פישטו את המצב יתר על המידה, ולא מתייחסים למצב שבו אין את הפריט במלאי.            הרחיבו את הפונקציות get_stock כך שיחזירו 0 במידה והפריט לא נמצא במלאי.                                    חשוב!            פתרו לפני שתמשיכו!              הגדרה  מה זה מילון? מילון הוא סוג ערך בפייתון.תכליתו היא ליצור קשר בין סדרה של נתונים שנקראים "מפתחות", לבין סדרה אחרת שנקראת "ערכים".לכל מפתח יש ערך שעליו הוא מצביע.     ישנן דוגמאות אפשריות רבות לקשרים שכאלו:    קשר בין ערים בעולם לבין כמות האנשים שחיים בהן.    קשר בין ברקוד של מוצרים בחנות לבין כמות הפריטים במלאי מכל מוצר.     קשר בין מילים לבין רשימת הפירושים שלהן באבן־שושן. לערך המצביע נקרא מפתח (key). זה האיבר מבין זוג האיברים שעל־פיו נשמע הגיוני יותר לחפש דברים:    העיר שבה אנחנו רוצים לדעת מה כמות התושבים    הברקוד שעבורו אנחנו רוצים לדעת כמה מוצרים קיימים במלאי    המילה שאת הפירושים שלה אנחנו רוצים למצוא לערך השני מבין שני הערכים בזוג, נקרא.... ובכן, ערך (value). זה הנתון שנרצה להסיק מתוך המפתח:    כמות התושבים בעיר    כמות המוצרים הקיימים במלאי עבור ברקוד מסוים    הפירושים של המילה במילון אם כך, מילון הוא בסך־הכל אוסף של זוגות שכאלו: מפתחות וערכים.  הבסיס  יצירת מילון ניצור מילון חדש:<jupyter_code>ages = {'Yam': 27, 'Methuselah': 969, 'Baby Groot': 3}<jupyter_output><empty_output><jupyter_text>במילון הזה ישנם שלושה ערכים: הגיל של ים, של מתושלח ושל בייבי־גרוט.המפתחות במילון הזה הם Yam (הערך הקשור למפתח הזה הוא 27), Methuselah (עם הערך 969) ו־Baby Groot (אליו הוצמד הערך 3). יצירת המילון התבצעה בצורה הבאה:     פתיחת סוגריים מסולסלים.    יצירת זוגות של מפתחות וערכים, מופרדים בפסיק:                    המפתח.            הפרדה באמצעות נקודותיים.            הערך.                סגירת סוגריים מסולסלים.         דוגמה למילון שכולל 3 ערכים. ניתן ליצור מילון ריק בעזרת פתיחה וסגירה של סוגריים מסולסלים:<jupyter_code>age_of_my_elephants = {}<jupyter_output><empty_output><jupyter_text>צרו מילון עבור המלאי בחנות של אדון קשטן.                                    חשוב!            פתרו לפני שתמשיכו!              אחזור ערך נזכר כיצד מאחזרים ערך מתוך רשימה:<jupyter_code>names = ['Yam', 'Mathuselah', '<NAME>']<jupyter_output><empty_output><jupyter_text>כדי להשיג את הערך שנמצא במקום 2 ברשימה names, אני אכתוב:<jupyter_code>names[2]<jupyter_output><empty_output><jupyter_text>עד כאן הכל מוכר.ניקח את המילון שמייצג את המלאי בחנות של אדון קשטן:<jupyter_code>items = {'banana': 2, 'apple': 3, 'carrot': 4}<jupyter_output><empty_output><jupyter_text>על מנת להשיג את המלאי שנמצא במקום שבו המפתח הוא 'banana', ארשום את הביטוי הבא:<jupyter_code>items['banana']<jupyter_output><empty_output><jupyter_text>מכיוון שבמילון המפתח הוא זה שמצביע לערך ולא להיפך, אפשר לאחזר ערך לפי מפתח, אבל אי אפשר לאחזר מפתח בעזרת ערך.                                          ביום־יום, השתמשו במילה "בְּמָקוֹם" (b'e-ma-qom) כתחליף למילים סוגריים מרובעים.            לדוגמה: עבור שורת הקוד האחרונה, אימרו items במקום banana.              הוספה ועדכון ניתן להוסיף מפתח וערך למילון, באמצעות השמת הערך אל המילון במקום של המפתח.אם, לדוגמה, יש לנו במלאי מלון אחד.המפתח הוא melon והערך הוא 1, ולכן נשתמש בהשמה הבאה:<jupyter_code>items['melon'] = 1<jupyter_output><empty_output><jupyter_text>אם הגיעו עוד 4 מלונים לחנות של אדון קשטן, נוכל לעדכן את מלאי המלונים באמצעות השמה למקום הנכון במילון:<jupyter_code>items['melon'] = items['melon'] + 4<jupyter_output><empty_output><jupyter_text>כללי המשחק     לא יכולים להיות 2 מפתחות זהים במילון.    המפתחות במילון חייבים להיות immutables.    אנחנו נתייחס למילון כאל מבנה ללא סדר מסוים (אין "איבר ראשון" או "איבר אחרון").                                           בגרסאות האחרונות של פייתון מילון הפך להיות מבנה מסודר, בו סדר האיברים הוא סדר ההכנסה שלהם למילון.            למרות זאת, רק במצבים נדירים נצטרך להתייחס לסדר שבו האיברים מסודרים במילון, ובשלב זה נעדיף שלא להתייחס לתכונה הזו.              סיכום ביניים     מילון הוא מבנה שבנוי זוגות־זוגות: יש ערכים ומפתחות, ולכל מפתח יש ערך אחד.    אנחנו נתייחס למילון כאל מבנה ללא סדר מסוים. אין "איבר ראשון" או "איבר אחרון".     בניגוד לרשימה, כאן ה"מקום" אליו אנחנו פונים כדי לקבל ערך הוא המפתח, ולא מספר שמייצג את המקום הסידורי של התא.    בעזרת מפתח ניתן להגיע לערך המוצמד אליו, אבל לא להיפך.  מעבר על מילון  לולאת for מכיוון שמילון הוא iterable, דרך מקובלת לעבור עליו היא באמצעות לולאת for.ננסה להשתמש בלולאת for על המילון, ונראה מה התוצאות:<jupyter_code>loved_animals = {'Alice': 'Cat', 'Mad hatter': 'Hare', 'Achiles': 'Tortoise'}
for something in loved_animals:
    print(something)<jupyter_output>Alice
Mad hatter
Achiles<jupyter_text>נראה שקיבלנו רק את המפתחות, בלי הערכים.    נסיק מכאן שמילון הוא אמנם iterable, אך בכל חזרור הוא מחזיר לנו רק את המפתח, בלי הערך.     אנחנו כבר יודעים איך משיגים את הערך של מפתח מסוים.    נוכל להשתמש בידע הזה כדי לקבל בכל חזרור גם את המפתח, וגם את הערך:<jupyter_code>loved_animals = {'Alice': 'Cat', 'Mad hatter': 'Hare', 'Achiles': 'Tortoise'}
print('loved_animals items:')
for key in loved_animals:
    value = loved_animals[key]
    print(f"{key:10} -----> {value}.")  # תרגיל קטן: זהו את הטריק שגורם לזה להראות כל־כך טוב בהדפסה<jupyter_output>loved_animals items:
Alice      -----> Cat.
Mad hatter -----> Hare.
Achiles    -----> Tortoise.<jupyter_text>אבל זה לא נראה אלגנטי מי־יודע־מה, ומרגיש שיש פתרון טוב יותר. הפעולה items על מילונים יכולה לעזור במקרה הזה.הפעולה מחזירה זוגות איברים, כאשר בכל זוג האיבר הראשון הוא המפתח והאיבר השני הוא הערך.<jupyter_code>print(list(loved_animals.items()))<jupyter_output>[('Alice', 'Cat'), ('Mad hatter', 'Hare'), ('Achiles', 'Tortoise')]<jupyter_text>מאחר שמדובר פה על איברים שבאים בזוגות, נוכל להשתמש בפריקת איברים שלמדנו בשיעור על לולאות for:<jupyter_code>print('loved_animals items:')
for key, value in loved_animals.items():
    print(f"{key:10} -----> {value}.")<jupyter_output>loved_animals items:
Alice      -----> Cat.
Mad hatter -----> Hare.
Achiles    -----> Tortoise.<jupyter_text>בלולאה שמופיעה למעלה ניצלנו את העובדה שהפעולה items מחזירה לנו איברים בזוגות: מפתח וערך.בכל חזרור, אנחנו מכניסים למשתנה key את האיבר הראשון בזוג, ולמשתנה value את האיבר השני בזוג.נוכל להיות אפילו יותר מנומסים ולתת למשתנים הללו שמות ראויים:<jupyter_code>print('loved_animals items:')
for character, animal in loved_animals.items():
    print(f"{character:10} -----> {animal}.")<jupyter_output>loved_animals items:
Alice      -----> Cat.
Mad hatter -----> Hare.
Achiles    -----> Tortoise.<jupyter_text>מחיקת איבר במילון לפעמים עולה צורך למחוק ממילון מפתח ואת הערך שקשור אליו.כפי שאולי ניחשתם, אין אפשרות למחוק רק את המפתח או רק את הערך – הם באים יחד.נרצה למחוק מפתח וערך מהמילון כשחשוב לנו לחסוך מקום בזכרון המחשב, או כשהם כבר לא רלוונטיים ומפריעים לנו.  מילת המפתח del הדרך הראשונה למחוק מפתח וערך ממילון היא להשתמש במילת המפתח del, שטרם הכרנו.מילת המפתח del מגיעה מהמילה delete (למחוק).נציין את שם המילון ואת המפתח שנרצה למחוק:<jupyter_code>loved_animals = {'Alice': 'Cat', 'Mad hatter': 'Hare', 'Achiles': 'Tortoise'}
del loved_animals['Achiles']
print(loved_animals)<jupyter_output>{'Alice': 'Cat', 'Mad hatter': 'Hare'}<jupyter_text>אפשר להשתמש במילת המפתח del גם כדי למחוק תאים מרשימה או למחוק משתנים, למרות שהשימושים הללו נדירים למדי.  הפעולה pop פעמים רבות נרצה לקבל את הערך של המפתח שאנחנו מוחקים.למרבה הצער, מילת המפתח del מוחקת את המפתח והערך בלי להחזיר שום מידע על הנתונים שנמחקו.נוכל לקבל את הערך שנמחק בכל־זאת בעזרת הפעולה pop, שחוץ מלמחוק זוג של מפתח וערך, גם מחזירה את הערך שמחקה:<jupyter_code>loved_animals = {'Alice': 'Cat', 'Mad hatter': 'Hare', 'Achiles': 'Tortoise'}
deleted_value = loved_animals.pop('Achiles')
print(loved_animals)
print(deleted_value)<jupyter_output>{'Alice': 'Cat', 'Mad hatter': 'Hare'}
Tortoise<jupyter_text>מפתחות שלא קיימים  הבעיה מילונים הם טיפוסים קצת רגישים. הם לא אוהבים כשמזכירים להם מה אין בהם.אם ננסה לפנות למילון ולבקש ממנו מפתח שאין לו, נקבל הודעת שגיאה.בפעמים הראשונות שתתעסקו עם מילונים, יש סיכוי לא מבוטל שתקבלו KeyError שנראה כך:<jupyter_code>empty_dict = {}
empty_dict['Achiles']<jupyter_output><empty_output><jupyter_text>in במילונים יש מספר דרכים לגשת לבעיה הזו.דרך אפשרית אחת היא לבדוק שהמפתח קיים לפני שאנחנו ניגשים אליו:<jupyter_code>loved_animals = {'Alice': 'Cat', 'Mad hatter': 'Hare', 'Achiles': 'Tortoise'}
print('Achiles' in loved_animals)<jupyter_output>True<jupyter_text>כאן השתמשנו באופרטור in כדי לבדוק האם מפתח מסוים נמצא במילון.לרוב, גם נבקש את הערך לאחר שבדקנו שהוא קיים:<jupyter_code>loved_animals = {'Alice': 'Cat', 'Mad hatter': 'Hare', 'Achiles': 'Tortoise'}

if 'Achiles' in loved_animals:
    value = loved_animals['Achiles']
else:
    value = 'Pony'

print(value)<jupyter_output>Tortoise<jupyter_text>בקוד שלמעלה, השתמשנו באופרטור ההשוואה in כדי לבדוק האם מפתח מסוים ("אכילס") קיים בתוך המילון שיצרנו בשורה הראשונה.אם הוא נמצא שם, חילצנו את הערך שמצומד לאותו מפתח (ל"אכילס"). אם לא, המצאנו ערך משלנו – "פוני".                                          מעבר על מילון יחזיר בכל חזרור מפתח מהמילון, ללא הערך הקשור אליו.            מהסיבה הזו, אופרטור ההשוואה in יבדוק רק האם קיים מפתח מסוים במילון, ולא יבדוק האם ערך שכזה קיים.                                                      כתבו פונקציה שמקבלת שלושה פרמטרים: מילון, מפתח וערך ברירת־מחדל.            הפונקציה תחפש במילון את המפתח, ובמידה והוא קיים תחזיר את הערך שלו.            אם המפתח לא קיים במילון, הפונקציה תחזיר את ערך ברירת־המחדל.                                    חשוב!            פתרו לפני שתמשיכו!             ננסה לכתוב את הרעיון בקוד שלמעלה כפונקציה כללית:<jupyter_code>def get_value(dictionary, key, default_value):
    if key in dictionary:
        return dictionary[key]
    else:
        return default_value<jupyter_output><empty_output><jupyter_text>הפונקציה שלמעלה מקבלת מילון, מפתח וערך ברירת־מחדל.אם היא מוצאת את המפתח במילון, היא מחזירה את הערך של אותו מפתח.אם היא לא מוצאת את המפתח במילון, היא מחזירה את ערך ברירת המחדל שנקבע. נבדוק שהפונקציה עובדת:<jupyter_code>loved_animals = {'Alice': 'Cat', 'Mad hatter': 'Hare', 'Achiles': 'Tortoise'}
print("Mad hatter: " + get(loved_animals, 'Mad hatter', 'Pony'))
print("Queen of hearts: " + get(loved_animals, 'Queen of hearts', 'Pony'))<jupyter_output>Mad hatter: Hare
Queen of hearts: Pony<jupyter_text>ובכן, זו פונקציה כייפית. כמה נוח היה לו היא הייתה פעולה של מילון.  הפעולה get במילונים מי היה מאמין, יש פעולה שכזו במילונים! ננסה להפעיל אותה על המילון שלנו.שימו לב לצורת הקריאה לפעולה, ששונה מהקריאה לפונקציה שכתבנו למעלה – שם המשתנה של המילון בא לפני שם הפעולה. מדובר בפעולה, ולא בפונקציה:<jupyter_code>loved_animals = {'Alice': 'Cat', 'Mad hatter': 'Hare', 'Achiles': 'Tortoise'}
print("Mad hatter: " + loved_animals.get('Mad hatter', 'Pony'))
print("Queen of hearts: " + loved_animals.get('Queen of hearts', 'Pony'))<jupyter_output>Mad hatter: Hare
Queen of hearts: Pony<jupyter_text>טריק קסום אחרון שנראה הוא שהפעולה get רחמנית ממש, ויודעת להתמודד גם אם לא נותנים לה ערך ברירת־מחדל.אם תספקו רק את שם המפתח שממנו תרצו לאחזר ערך, היא תחפש אותו ותחזיר את הערך שלו אם הוא קיים.אם המפתח לא קיים ולא סופק ערך ברירת־מחדל, היא תחזיר את הערך None:<jupyter_code>loved_animals = {'Alice': 'Cat', 'Mad hatter': 'Hare', 'Achiles': 'Tortoise'}
print(loved_animals.get('Mad hatter'))
print(loved_animals.get('Queen of hearts'))<jupyter_output>Hare
None<jupyter_text>הערך המיוחד None הוא דרך פייתונית להגיד "כלום".            ניתן לדמיין אותו כמו רִיק (וָקוּם). לא הערך המספרי אפס, לא False. פשוט כלום.              מבנים מורכבים נפוצים העולם לעיתים מורכב, וניסיון לארגן מידע רב יכול ליצור מבני נתונים שנראים מסובכים במבט ראשון.  רשימת מילונים נראה, לדוגמה, דרך לייצג מאגר קטן של משתמשים:<jupyter_code>users = [
    {'name': '<NAME>', 'age': 34, 'country': 'Unitee States'},
    {'name': '<NAME>', 'age': 63, 'country': 'Netherlands', 'spouse': 'Kim Knapp'},
    {'name': '<NAME>', 'age': 70, 'country': 'United States', 'spouse': 'Parris McBride'},
]<jupyter_output><empty_output><jupyter_text>כדי לסגנן את הקוד שלנו, הרבה פעמים נרד שורה גם כשלא חייבים.            נפוץ מאוד לרדת שורה במבנים ארוכים אחרי שפתחנו סוגריים – פייתון מבינה שמדובר באותה שורה.             למעלה מוצגת רשימה שמכילה 3 מילונים. אפשר לעבור עליה בעזרת לולאה כמו על כל רשימה אחרת.נדפיס את השמות של כל אחד מהמשתמשים:<jupyter_code>for user in users:
    print(user['name'])<jupyter_output><NAME>
<NAME>
<NAME><jupyter_text>נזהר במקרה שיש מפתח שעלול לא להופיע באחד המילונים.לדוגמה, לסקרלט ג'והנסון אין בן־זוג, ולכן כשהלולאה הבאה תגיע אליה היא תקפיץ שגיאה:<jupyter_code>for user in users:
    print(user['spouse'])<jupyter_output><empty_output><jupyter_text>נראה דוגמה לטיפול במקרה שכזה בעולם האמיתי:<jupyter_code>for user in users:
    if 'spouse' in user:
        print(f"{user['name']}'s spouse is {user['spouse']}.")
    else:
        print(f"{user['name']} has no spouse.")<jupyter_output><NAME>ohansson has no spouse.
<NAME>'s spouse is <NAME>.
<NAME>'s spouse is Parris McBride.<jupyter_text>או שנרמה קצת בעזרת הפעולה get:<jupyter_code>for user in users:
    spouse = user.get('spouse', 'unknown')
    print(f"{user['name']}'s spouse is {spouse}.")<jupyter_output><NAME>'s spouse is unknown.
<NAME>'s spouse is <NAME>.
<NAME>'s spouse is <NAME>.<jupyter_text>ערכים מרובים במפתח אחד  מילון שערכיו הם רשימות אנחנו רוצים ליצור תוכנה לניהול ספרייה, בה הספרים מחולקים לפי שם המחבר.בשלב הנוכחי ביקשו מאיתנו לשמור רק את שמות הספרים עבור כל מחבר.אנחנו רוצים את האפשרות לשלוף את שמות הספרים לפי שם המחבר, ושיהיה קל להוסיף ולהוריד ספרים מרשימת ספריו של כל מחבר.                                          השקיעו 5 דקות כדי לחשוב איך הייתם בונים ספרייה שכזו בעזרת סוגי הנתונים שלמדתם.            בונוס: הגדירו ספרייה שכזו וממשו פונקציה שמאפשרת להוסיף ולהסיר ספרים עבור כל מחבר.                                    חשוב!            פתרו לפני שתמשיכו!             נחשוב על הדרישות שהעלו לנו:     אנחנו צריכים להיות מסוגלים למצוא את רשימת הספרים לפי שם המחבר.    אנחנו צריכים להיות מסוגלים לערוך (להוסיף, להוריד) את הספרים שקיימים עבור כל מחבר. עבור הדרישה הראשונה, נשמע שהמבנה המתאים ביותר הוא מילון שממפה את שם המחבר לרשימת הספרים שלו.עבור הדרישה השנייה, נשמע שהמבנה המתאים ביותר יהיה רשימה – סוג גמיש שקל לערוך את האיברים שבו (לעומת tuple, לדוגמה). נבנה מילון שכזה לדוגמה:<jupyter_code>library = {
    '<NAME>': ['Pride and Prejudice', 'Sense and Sensibility', 'Mansfield Park', 'Emma'],
    '<NAME>': ['The Book Thief', 'The Messenger'],
    '<NAME>': ['1984', 'Animal Farm'], 
    '<NAME>': ['Gone with the Wind'],
    '<NAME>': ['The Hitchhiker\'s Guide to the Galaxy', 'The Restaurant at the End of the Universe',
                      'Life, the Universe and Everything', 'So Long, and Thanks for All the Fish', 'Mostly Harmless',
                      'And Another Thing'],
    '<NAME>': ['The Kite Runner', 'A Thousand Splendid Suns', 'And the Mountains Echoed'],
    '<NAME>': ['To kill a mockingbird', 'Go Set a Watchman']
}<jupyter_output><empty_output><jupyter_text>בהנתן הדרישות, תראו כמה קל לתפעל את הספרייה:<jupyter_code>def view_books(library, author_name):
    return library.get(author_name)

def add_book(library, author_name, book_name):
    authors_books = library[author_name]
    authors_books.append(book_name)

def remove_book(library, author_name, book_name):
    authors_books = library[author_name]
    authors_books.remove(book_name)

add_book(library, 'Douglas Adams', 'The Salmon of Doubt')
remove_book(library, 'Douglas Adams', 'And Another Thing')
print(view_books(library, 'Douglas Adams'))<jupyter_output>["The Hitchhiker's Guide to the Galaxy", 'The Restaurant at the End of the Universe', 'Life, the Universe and Everything', 'So Long, and Thanks for All the Fish', 'Mostly Harmless', 'The Salmon of Doubt']<jupyter_text>מילון שערכיו הם מילונים הדרישות של בעלי הספרייה השתנו.הם מבקשים שהפעם, בזמן שאנחנו שומרים על הסידור לפי שמות הסופרים, נוכל לקבל בנוסף לשם הספר את הפרטים הבאים:     תאריך היציאה    רשימת הז'אנרים    כמות במלאי נראה דוגמה למבנה נתונים שכזה.<jupyter_code>library = {
    'Jane Austen': {
        'Pride and Prejudice': {'released': '1813-01-28', 'genres': ['Classic Regency novel'], 'stock': 12},
        'Sense and Sensibility': {'released': '1813-01-28', 'genres': ['Romance novel'], 'stock': 5},
        'Mansfield Park': {'released': '1813-01-28', 'genres': ['Bildungsroman'], 'stock': 6},
        'Emma': {'released': '1813-01-28', 'genres': ['Novel of manners'], 'stock': 19}
    },
    '<NAME>': {
        'The Book Thief': {'released': '1813-01-28', 'genres': ['Novel-Historical Fiction'], 'stock': 4},
        'The Messenger': {'released': '1813-01-28', 'genres': ['Fiction'], 'stock': 0}
    },
    '<NAME>': {
        '1984': {'released': '1813-01-28', 'genres': ['Dystopian', 'Political fiction', 'Social science fiction'], 'stock': 1},
        'Animal Farm': {'released': '1813-01-28', 'genres': ['Political satire'], 'stock': 7}
    }
}<jupyter_output><empty_output><jupyter_text>מה היתרונות שנובעים מהבחירה שלנו לייצג הנתונים בצורה כזו? מה החסרונות?            אם הייתה לכם ספרייה משלכם, כיצד הייתם מסדרים ומייצגים את הנתונים?                                    חשוב!            פתרו לפני שתמשיכו!              מתי להשתמש לולאת for יוצרת מבנה אלגנטי וקריא, ומתכנתים רבים מעדיפים אותה על־פני לולאת while.ננסה לעמוד על ההבדלים בין הלולאות:  דוגמאות נוספות  דוגמאות מילוליות נוספות     עבור כל עמוד בספר – קרא את העמוד.    עבור כל צלחת – הכנס אותה מתחת למים חמים, שפשף אותה היטב עם סקוטץ' ספוג בסבון, נגב אותה עם מגבת יבשה ושים אותה במתקן לייבוש כלים.    חשב את הגובה הממוצע של תלמיד, מתוך רשימה של 1000 תלמידים.    בליל כל הקדושים, התחפש, צא החוצה, ועבור כל בית ברחוב: לך לבית, צלצל בפעמון, אמור "ממתק או תעלול", קח ממתק ואמור תודה.  דוגמאות קוד  סכום רשימה<jupyter_code>def total(numbers):
    total = 0
    for number in numbers:
        total = total + number
    return total
    

print(total([1, 2, 3]))<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.0908004778972521, 'fraction_numerical': 0.008960573476702509, 'mean_word_length': 3.5884461311406284, 'pattern_counts': {'":': 0, '<': 157, '<?xml version=': 0, '>': 169, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 1, 'word_list_counts': {'cursed_substrings.json': 21, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '37', 'dir': 'jupyter-structured-clean-dedup', 'id': '164910', 'license': 'MIT', 'n_tokens_mistral': 15146, 'n_tokens_neox': 13518, 'n_words': 2676, 'path': 'week4/2_Dictionaries.ipynb', 'repo_name': 'FlowerPower2/Notebooks', 'size': '21990'}