פעולות על רשימות

הקדמה

עד כה למדנו שישנם שני אופרטורים חשבוניים שעובדים על רשימות: חיבור וכפל.
חיבור משרשר רשימה אחת לאחרת, וכפל משרשר רשימה לעצמה כמה פעמים.
ניזכר בדוגמאות:


In [ ]:
numbers = [1, 2]

In [ ]:
numbers = numbers + [3, 4]
print(numbers)

In [ ]:
numbers = numbers * 2
print(numbers)

למדנו גם שאפשר להשוות בין רשימות בעזרת אופרטורי השוואה, שעליהם למדנו בשיעור על ביטויים בוליאניים.


In [ ]:
numbers == [1, 2, 3, 4]

In [ ]:
1 in numbers

In [ ]:
[1, 2] in numbers

השבוע כבר הספקנו ללמוד על חיתוכים (Slicing), כך שיש לנו כבר ידע רב באשר לשימוש ברשימות.


In [ ]:
print(numbers)
print("Flip the order: " + str(numbers[::-1]))
print("Only first 4 items: " + str(numbers[:4]))
print("Only first 4 items, in reversed order:: " + str(numbers[3::-1]))

למרות כל הידע המועיל שצברנו עד כה, טרם נגענו בפעולות השייכות לנתונים מסוג רשימה.
הפעולות האלו יתווספו לארגז הכלים שלנו, יקלו על כתיבת הקוד ויעשו אותו קריא יותר.

פעולות על רשימה

נגדיר רשימה שתשמש אותנו לדוגמאות:


In [ ]:
animals = ['pig', 'shark', 'lion']

במהלך הרצת הדוגמאות נשים לב שפעולות על הרשימה משפיעות ישירות על הרשימה עצמה.
זה אומר שלא נצטרך להשתמש בהשמה כדי לערוך את הרשימה שעליה אנחנו עובדים.

הוספת איבר

רשימה היא סוג נתונים נוח לשימוש, בין היתר כיוון שניתן להוסיף לה כמה איברים שנרצה.
נוכל להוסיף איבר לסוף הרשימה באמצעות הפעולה append:


In [ ]:
animals.append('duck')
print(animals)

הפעולה הזו תשיג תוצאה דומה לקוד שכתבנו עד היום בדרך טיפה פחות אלגנטית:


In [ ]:
animals = animals + ['duck']
print(animals)

שימו לב שבניגוד לשורה שמופיעה למעלה, append מאפשרת להוסיף בכל פעם איבר אחד בלבד.
ניסיון להעביר לפעולה append רשימה, נניח, יוסיף את הרשימה המשנית כולה כאיבר אחד בסוף הרשימה הראשית:


In [ ]:
animals.append(['duck', 'zebra'])
print(animals)

כתבו פונקציה שמקבלת מספר, ומחזירה רשימה של כל המספרים החיוביים הזוגיים עד אותו מספר.

הסרת איבר

נוכל להסיר איבר מסוף הרשימה באמצעות קריאה לפעולה pop:


In [ ]:
animals.pop()
print(animals)

הפעולה הזו תשיג תוצאה דומה לקוד שכתבנו עד היום בצורה המסורבלת הבאה:


In [ ]:
animals = animals[:-1]
print(animals)

הפעולה pop מחזירה את הערך שהוציאה, כך שניתן לשמור אותו בצד:


In [ ]:
last_animal = animals.pop()
print(last_animal)
print(animals)

הפעולה גם מאפשרת לנו לבחור את המקום שממנו אנחנו מעוניינים להוציא את הערך.
נעשה זאת בעזרת העברת ארגומנט עם מיקום הערך שאנחנו רוצים להוציא מהרשימה:


In [ ]:
first_animal = animals.pop(0)
print(first_animal)
print(animals)

כדי להסיר יותר מאיבר אחד, ייתכן שעדיין תעדיפו להשתמש בחיתוך רשימות.

כתבו פונקציה שמקבלת רשימה, ומחזירה רשימה בסדר איברים הפוך.
השתמשו בפעולה pop.
לדוגמה: אם תועבר לפונקציה הרשימה [3, 2, 1], הפונקציה תחזיר [1, 2, 3].

הוספה של כמה איברים

נוכל להוסיף יותר מאיבר אחד בשימוש יחיד בפעולה extend:


In [ ]:
animals_to_add = ['duck', 'pig', 'zebra']
animals.extend(animals_to_add)
print(animals)

במבט ראשון, הפעולה תשיג תוצאה דומה לשרשור רשימות:


In [ ]:
animals_to_add = ['duck', 'pig', 'zebra']
animals = animals + animals_to_add
print(animals)

אבל אחד היתרונות המובהקים של extend הוא שניתן להעביר לה כארגומנט כל iterable שהוא.
הפעולה extend תפרק את ה־iterable ותוסיף כל איבר בנפרד לרשימה המקורית:


In [ ]:
string_numbers = ['1', '2', '3', '4', '5']
string_numbers.extend('6789')  # string as argument
string_numbers.extend(['10', '11'])  # list as argument
print(string_numbers)

כתבו פונקציה שמקבלת רשימה, ומחזירה רשימה המכילה את הרשימה המקורית, ומייד אחריה את אותה רשימה בסדר הפוך.
לדוגמה: עבור הרשימה [1, 2, 3] תוחזר הרשימה: [1, 2, 3, 3, 2, 1]

ספירת איברים

כאן לא תמצאו הפתעות מיוחדות. הפעולה count מחזירה את מספר האיברים ברשימה, שזהים לאיבר שהעברתם לה כארגומנט.
נשמע לכם מוכר? נכון! למחרוזות יש פעולה עם שם זהה שעושה בדיוק אותו דבר.


In [ ]:
print(animals)
zebra_counter = animals.count('zebra')
print(f"I've found {zebra_counter} zebras in your zoo!")

מציאת איבר

גם הפעולה הזו אמורה להישמע לכם מוכרת.
הפעולה index מוצאת את המופע הראשון של האיבר שהעברתם לה כארגומנט.
כן, גם הפעם למחרוזות יש פעולה באותו שם, שעושה בדיוק אותו דבר.


In [ ]:
print(animals)
zebra_finder = animals.index('zebra')
print(f"The first zebra in your zoo hides in park number {zebra_finder}")

כמו בפעולת index על מחרוזות, גם כאן הפעולה תזרוק שגיאה אם הערך לא נמצא.

כתבו פונקציה שמקבלת רשימה, ומחזירה את מיקום המופע האחרון של האיבר הראשון ברשימה.
לדוגמה, עבור הרשימה [1, 2, 3, 5, 1, 2] החזירו 4, כיוון ש־1 מופיע פעם אחרונה במקום 4 ברשימה.

מחיקת איבר (שוב?)

הפעם נשתמש בפעולה remove, שבניגוד לפעולה pop מוחקת איבר לפי הערך שלו ולא לפי המיקום שלו.
נשים לב שהפעולה תמחק את האיבר הראשון השווה לערך שהועבר כארגומנט, ולא את כל המופעים של אותו ערך.


In [ ]:
print(f"Animals: {animals}")
while 'pig' in animals:
    animals.remove('pig')
print(f"Kosher Zoo: {animals}")

קבלו פונקציה שמקבלת רשימה של חיות, ומחזירה רשימה שבה אין מופעים של החיות camel, rabbit ו־pig.
לדוגמה, עבור הרשימה: ['camel', 'camel', 'dove', 'pig', 'camel'] תוחזר הרשימה: ['dove']

סידור רשימה

אחת הפעולות הנוחות ביותר שאפשר לבצע על רשימה היא sort, שמסדרת לנו את האיברים ברשימה.
אם האיברים הם מחרוזות, הרשימה תסודר בסדר לקסיקוגרפי (אלפביתי).
אם האיברים ברשימה הם מספרים (שלמים, עשרוניים או גם וגם), הרשימה תסודר מתמטית מהקטן לגדול.
אם הרשימה מורכבת מסוגים שונים של איברים שאין ביניהם הגדרת שוויון ברורה (כמו מספרים ומחרוזות), פעולת הסידור תיכשל ותזרוק שגיאה.


In [ ]:
print(animals)
animals.sort()
print(animals)

In [ ]:
strange_list = [1, 2, 3, 'dag maluah']
strange_list.sort()

טעות נפוצה היא השמת התוצאה של sort חזרה למשתנה.
כיוון שהפעולה sort משנה את מיקום האיברים בתוך הרשימה ולא מחזירה ערך, השמה חזרה למשתנה תמחק את ערכו.

תרגול: קבלו מהמשתמש 10 מספרים. מצאו את הערך השלישי הגדול ביותר.
לדוגמה, עבור הקלט הבא: 5, 1, 6, 2, 3, 4, 8, 7, 10, 9, החזירו 8.

הוספת איבר במקום מסוים

תרגול: קראו בתיעוד של פייתון על הפעולה insert השייכת לערכים מסוג רשימה.
הוסיפו דג מימין לכריש (shark) שברשימת animals.

תרגילים נוספים

חוטש

כתבו פונקציה שמקבלת רשימה של רשימות, ומחזירה רשימה שטוחה והפוכה של כל האיברים.
לדוגמה: עבור הרשימה [[1, 2, 3], [4, 5, 6]] החזירו [6, 5, 4, 3, 2, 1].

רשימת תיקונים

לפניכם קוד שמטרתו היא מציאת המספר הקטן ביותר שהמשתמש הזין.
הכמנו בקוד 3 טעויות. מצאו אותן ותקנו אותן כך שהקוד יפעל.


In [ ]:
def get_minimum(numbers):
    numbers = numbers.sort()
    return numbers[-1]

numbers = '8, 9, 10, 11, 12'.split(', ')
minimum_number = get_minimum(numbers)
print(f"The minimum number is {minimum_number}")