list — רשימה: יצירה, גישה, הוספה, מחיקה, חיפוש ומעבר

מטרות השיעור
  • ליצור list ולגשת לאיברים לפי אינדקס חיובי ושלילי
  • להוסיף ולמחוק איברים עם append, insert, remove, pop ו-del
  • לחפש ברשימה עם in, index ו-count
  • לעבור על רשימה בלולאה, כולל עם enumerate, ולמיין אותה

מה נלמד?

list (רשימה) היא מבנה הנתונים הנפוץ ביותר ב-Python. כבר השתמשנו בה בקצרה. היום נלמד אותה כמו שצריך:

  • יצירה וגישה לאיברים.
  • הוספה, מחיקה ושינוי.
  • חיפוש.
  • מעבר בלולאה ומיון.

למה צריך את זה?

כמעט כל תוכנה מחזיקה אוספים: רשימת סטודנטים, מוצרים בעגלה, הזמנות של היום, שורות מקובץ, תוצאות משאילתת Database (נושא Backend ומסדי נתונים). כשהמספר לא ידוע מראש, אי אפשר להחזיק משתנה נפרד לכל פריט (student1, student2…). רשימה מחזיקה כמה שצריך, בסדר מסוים.

הסבר מהבסיס

מהי list?

list היא אוסף מסודר של ערכים:

  • מסודר (Ordered) — לכל איבר יש מיקום קבוע, האינדקס (Index).
  • ניתן לשינוי (Mutable) — אפשר להוסיף, למחוק ולשנות איברים אחרי היצירה.
  • מאפשר כפילויות — אותו ערך יכול להופיע כמה פעמים.
  • כל טיפוס — אפשר לערבב ([1, "a", True]), אבל בדרך כלל רשימה מחזיקה פריטים מאותו סוג.
אנלוגיה: רכבת

רשימה היא רכבת עם קרונות ממוספרים. כל קרון (איבר) נושא מטען (ערך). הקרון הראשון הוא מספר 0 ולא 1. אפשר לחבר קרון בסוף (append), להכניס קרון באמצע (insert), או לנתק קרון (remove/pop).

אינדקסים

fruits = ["apple", "banana", "cherry", "date"]
index:       0         1         2        3
negative:   -4        -3        -2       -1
  • הספירה מתחילה מ-0.
  • אינדקס שלילי סופר מהסוף: -1 = האחרון, -2 = לפני האחרון.
  • אינדקס שלא קיים ‏←‏ IndexError.

תחביר

# create
empty = []
numbers = [10, 20, 30]

# access and change
numbers[0]          # 10 - first item
numbers[-1]         # 30 - last item
numbers[1] = 25     # change an item
len(numbers)        # 3 - how many items

# add
numbers.append(40)       # add to the end
numbers.insert(0, 5)     # insert at index 0, pushing the rest right

# remove
numbers.remove(25)       # remove the FIRST item equal to 25
last = numbers.pop()     # remove and return the last item
first = numbers.pop(0)   # remove and return the item at index 0
del numbers[0]           # delete by index (returns nothing)
numbers.clear()          # remove everything

# search
30 in numbers            # True / False
numbers.index(30)        # index of the first 30 (ValueError if missing)
numbers.count(30)        # how many times 30 appears

# sort
numbers.sort()               # sorts THIS list in place
numbers.sort(reverse=True)   # descending
sorted(numbers)              # returns a NEW sorted list, original unchanged

מתודה (Method) היא פונקציה ש"שייכת" לאובייקט, ונקראת עם נקודה: numbers.append(40). נלמד על מתודות לעומק בנושא OOP. כרגע: “פעולה שהרשימה יודעת לעשות על עצמה”.

דוגמת קוד ראשונה

week-2/shopping_list.py:

shopping = ["milk", "bread", "eggs"]
print("Start:", shopping)

shopping.append("cheese")
print("After append:", shopping)

shopping.insert(1, "butter")
print("After insert:", shopping)

shopping.remove("bread")
print("After remove:", shopping)

print("First item:", shopping[0])
print("Last item:", shopping[-1])
print("Items count:", len(shopping))

פלט:

Start: ['milk', 'bread', 'eggs']
After append: ['milk', 'bread', 'eggs', 'cheese']
After insert: ['milk', 'butter', 'bread', 'eggs', 'cheese']
After remove: ['milk', 'butter', 'eggs', 'cheese']
First item: milk
Last item: cheese
Items count: 4

פירוק הקוד שורה אחר שורה

שורהמה קרה לרשימה
shopping = [...]יצירה עם 3 איברים: אינדקסים 0, 1, 2.
.append("cheese")נוסף בסוף. עכשיו 4 איברים.
.insert(1, "butter")נכנס באינדקס 1. מה שהיה שם (bread) ומה שאחריו זזו ימינה.
.remove("bread")נמחק לפי ערך: Python מחפשת את המופע הראשון של "bread" ומוחקת אותו.
shopping[0]האיבר הראשון.
shopping[-1]האיבר האחרון, בלי לדעת כמה יש.
len(shopping)מספר האיברים.

שימו לב: append, insert ו-remove משנות את הרשימה עצמה ולא מחזירות רשימה חדשה. לכן לא כותבים shopping = shopping.append(...) (על זה, בסעיף הטעויות).

דוגמה נוספת

ניהול תור לקופה: מעבר, חיפוש, pop ו-enumerate. week-2/queue.py:

queue = ["dana", "avi", "noa", "avi", "yossi"]

print("People in queue:", len(queue))
print("Is noa waiting?", "noa" in queue)
print("noa's position:", queue.index("noa") + 1)
print("How many times avi:", queue.count("avi"))

served = queue.pop(0)
print("Now serving:", served)

print("--- Remaining queue ---")
for position, name in enumerate(queue, start=1):
    print(position, name)

queue.sort()
print("Alphabetical:", queue)

פלט:

People in queue: 5
Is noa waiting? True
noa's position: 3
How many times avi: 2
Now serving: dana
--- Remaining queue ---
1 avi
2 noa
3 avi
4 yossi
Alphabetical: ['avi', 'avi', 'noa', 'yossi']

פירוק:

  • "noa" in queue — in עובר על הרשימה ובודק אם הערך קיים. מחזיר bool.
  • queue.index("noa") + 1 — index מחזיר את האינדקס (2). מוסיפים 1 כי לבני אדם “מקום שלישי” מתחיל מ-1.
  • queue.pop(0) — מוציא ומחזיר את הראשון. זה ההבדל מ-remove: pop נותן את הערך שהוצא, כדי שנוכל להשתמש בו (served).
  • enumerate(queue, start=1) — בכל סיבוב נותן זוג: מספר סידורי והאיבר. for position, name in ... מפרק את הזוג לשני משתנים. בלי start=1, הספירה מתחילה מ-0.
  • queue.sort() — ממיין את הרשימה עצמה, בסדר אלפביתי לטקסט ובסדר עולה למספרים.

טעות נפוצה

הטעות 1: להשים את התוצאה של מתודה שמשנה במקום.

names = ["noa", "avi"]
names = names.append("dana")
print(names)
None

append משנה את הרשימה ומחזירה None. השמנו את ה-None לתוך names, ואיבדנו את הרשימה! התיקון: names.append("dana") לבד. אותו דבר עם sort(), insert(), remove().

הטעות 2: Off-by-one באינדקס האחרון.

items = ["a", "b", "c"]
print(items[len(items)])
IndexError: list index out of range

len הוא 3, אבל האינדקס האחרון הוא 2. האחרון = items[-1] או items[len(items) - 1].

הטעות 3: remove על ערך שלא קיים.

items.remove("z")
ValueError: list.remove(x): x not in list

בודקים קודם: if "z" in items: items.remove("z").

הטעות 4: למחוק מרשימה תוך כדי מעבר עליה.

numbers = [1, 2, 2, 3]
for n in numbers:
    if n == 2:
        numbers.remove(n)
print(numbers)
[1, 2, 3]

ציפינו ל-[1, 3]. כשמוחקים איבר, כל האיברים זזים שמאלה, והלולאה “מדלגת” על האיבר הבא. הפתרון הבטוח: לבנות רשימה חדשה עם מה שרוצים לשמור:

numbers = [1, 2, 2, 3]
kept = []
for n in numbers:
    if n != 2:
        kept.append(n)
print(kept)   # [1, 3]

תרגול

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

תרגיל 1: אינדקסים

days = ["Sun", "Mon", "Tue", "Wed", "Thu"]

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

פלט צפוי:

Sun
Thu
Tue
הצג פתרון
days = ["Sun", "Mon", "Tue", "Wed", "Thu"]

print(days[0])
print(days[-1])
print(days[2])
Sun
Thu
Tue

אינדקסים מתחילים מ-0. אינדקס שלילי סופר מהסוף: -1 הוא האיבר האחרון.

תרגיל 2: רשימת קניות

התחילו מ-["milk", "bread"], ובצעו לפי הסדר:

  1. הוסיפו "eggs" לסוף.
  2. הוסיפו "butter" במקום הראשון.
  3. מחקו את "bread".
  4. הדפיסו את הרשימה ואת מספר הפריטים.

פלט צפוי:

['butter', 'milk', 'eggs']
3
הצג פתרון
shopping = ["milk", "bread"]

shopping.append("eggs")
shopping.insert(0, "butter")
shopping.remove("bread")

print(shopping)
print(len(shopping))
['butter', 'milk', 'eggs']
3
  • append — לסוף. insert(0, ...) — למקום מסוים.
  • remove — מוחק לפי ערך (את המופע הראשון).

תרגיל 3: תור

queue = ["dana", "avi", "noa", "avi", "yossi"]
  1. בדקו אם "noa" בתור, והדפיסו באיזה מקום היא (המקום הראשון הוא 1).
  2. הדפיסו כמה פעמים "avi" מופיע.
  3. שלפו את הראשון בתור והדפיסו Now serving: <name>, ואת מספר האנשים שנשארו.

פלט צפוי:

True
3
2
Now serving: dana
4
הצג פתרון
queue = ["dana", "avi", "noa", "avi", "yossi"]

print("noa" in queue)
print(queue.index("noa") + 1)
print(queue.count("avi"))

served = queue.pop(0)
print("Now serving:", served)
print(len(queue))
True
3
2
Now serving: dana
4

pop(0) גם מוחק וגם מחזיר את האיבר — לכן אפשר לשמור אותו במשתנה.

תרגיל 4: סטטיסטיקה על ציונים

grades = [78, 92, 55, 88, 100, 43, 67]

הדפיסו את הציון הגבוה, את הנמוך, את הממוצע (מעוגל לספרה אחת), ורשימה חדשה של הציונים שעברו (55 ומעלה) — בלי לשנות את grades.

פלט צפוי:

Highest: 100
Lowest: 43
Average: 74.7
Passed: [78, 92, 55, 88, 100, 67]
הצג פתרון
PASSING_GRADE = 55

grades = [78, 92, 55, 88, 100, 43, 67]

print("Highest:", max(grades))
print("Lowest:", min(grades))
print("Average:", round(sum(grades) / len(grades), 1))

passed = []
for grade in grades:
    if grade >= PASSING_GRADE:
        passed.append(grade)
print("Passed:", passed)
Highest: 100
Lowest: 43
Average: 74.7
Passed: [78, 92, 55, 88, 100, 67]

הדפוס של “רשימה חדשה + לולאה + append” הוא הדרך לסנן רשימה בלי לגעת במקורית.

תרגיל 5: מחיקה בזמן לולאה

numbers = [1, 2, 2, 3, 2, 4]
for n in numbers:
    if n == 2:
        numbers.remove(n)
print(numbers)

הכוונה הייתה למחוק את כל ה-2, אבל אחד נשאר. כתבו פונקציה remove_all(items, value) שמחזירה רשימה חדשה בלי אף מופע של value.

פלט צפוי:

[1, 3, 4]
הצג פתרון

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

def remove_all(items, value):
    result = []
    for item in items:
        if item != value:
            result.append(item)
    return result


print(remove_all([1, 2, 2, 3, 2, 4], 2))
[1, 3, 4]

סיכום

  • list = אוסף מסודר, ניתן לשינוי, עם כפילויות. נכתבת ב-[ ].
  • אינדקס מתחיל ב-0. -1 = האחרון. אינדקס לא קיים ‏←‏ IndexError.
  • הוספה: append (לסוף), insert (למקום). מחיקה: remove (לפי ערך), pop (לפי מיקום, ומחזירה), del.
  • חיפוש: in, index, count. מעבר: for, ו-enumerate כשצריך גם מספר.
  • מתודות שמשנות במקום (append, sort…) מחזירות None. sorted() מחזירה רשימה חדשה.
  • לא מוחקים מרשימה תוך כדי מעבר עליה. בונים רשימה חדשה.

דוקומנטציה רשמית