רשימות ב-Python

ב-Python יש סוג רשימה מובנה מצוין שנקרא 'list'. ליסטים לינאריים נכתבים בסוגריים מרובעים [ ]. רשימות פועלות באופן דומה למחרוזות – משתמשים בפונקציה len() ובסוגריים מרובעים [ ] כדי לגשת לנתונים, כאשר האלמנט הראשון נמצא ב-index 0. (אפשר לעיין במסמכים הרשמיים של הרשימה ב-python.org).

  colors = ['red', 'blue', 'green']
  print(colors[0])    ## red
  print(colors[2])    ## green
  print(len(colors))  ## 3

רשימת מחרוזות 'red' 'blue 'green'

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

  b = colors   ## Does not copy the list

גם colors וגם b מפנים לאותה רשימה

'הרשימה הריקה' היא רק זוג סוגריים ריקים [ ]. הסימן '+' משמש להוספת שתי רשימות, כך ש-[1, 2] + [3, 4] מניב [1, 2, 3, 4] (זה בדיוק כמו + עם מחרוזות).

FOR ו-IN

ביטויים מסוג *for* ו-*in* ב-Python הם שימושיים מאוד, והשימוש הראשון שלנו בהם יהיה עם רשימות. המבנה *for*‏ – for var in list – הוא דרך קלה לבדוק כל רכיב ברשימה (או באוסף אחר). אין להוסיף או להסיר פריטים מהרשימה במהלך המחזור.

  squares = [1, 4, 9, 16]
  sum = 0
  for num in squares:
    sum += num
  print(sum)  ## 30

אם אתם יודעים איזה סוג של פריטים נמצא ברשימה, תוכלו להשתמש בשם משתנה בלולאה שיאגר את המידע הזה, כמו 'num',‏ 'name' או 'url'. מאחר שלקוד Python אין תחביר אחר שמזכיר לכם סוגים שונים, שמות המשתנים הם אמצעי חשוב שעוזר לכם להבין בדיוק מה קורה. (זה קצת מטעה. ככל שתשתמשו יותר ב-Python, תראו הפניות לטיפים לגבי סוגים שמאפשרים לכם להוסיף מידע על הקלדה להגדרות הפונקציות. Python לא משתמשת בהצעות הסוג האלה כשהיא מפעילה את התוכניות שלכם. תוכנות אחרות, כמו סביבות פיתוח משולבות (IDE) וכלים לניתוח סטטי כמו לינטרים (linters) או בודקי טיפוסים, משתמשות בהן כדי לוודא שהפונקציות מופעלות עם ארגומנטים תואמים.

המבנה *in* בפני עצמו הוא דרך קלה לבדוק אם רכיב מופיע ברשימה (או באוסף אחר) – value in collection – בודק אם הערך נמצא באוסף, ומחזיר את הערך True/False.

  list = ['larry', 'curly', 'moe']
  if 'curly' in list:
    print('yay') ## yay

מבני for/in נפוצים מאוד בקוד Python, והם פועלים על סוגי נתונים שאינם רשימות, לכן כדאי לשנן את התחביר שלהם. יכול להיות שיש לכם הרגלים משפות אחרות שבהן אתם מתחילים להריץ חזרה ידנית על אוסף, אבל ב-Python צריך פשוט להשתמש ב-for/in.

אפשר גם להשתמש ב-for/in כדי לעבוד על מחרוזת. המחרוזת פועלת כרשימה של התווים שלה, כך ש-for ch in s: print(ch) מדפיס את כל התווים במחרוזת.

טווח

הפונקציה range(n) מחזירה את המספרים 0, 1, ... n-1, והפונקציה range(a, b) מחזירה את a, a+1, ... b-1 – עד למספר האחרון, אבל לא כולל אותו. השילוב של לולאת for עם הפונקציה range() מאפשר ליצור לולאת for מספרית מסורתית:

  ## print the numbers from 0 through 99
  for i in range(100):
    print(i)

יש וריאנט xrange()‎ שמאפשר להימנע מהעלות של יצירת הרשימה כולה במקרים רגישים לביצועים (ב-Python 3, ל-range()‎ תהיה התנהגות ביצועים טובה ותוכלו לשכוח מ-xrange()).

בזמן לולאת

ב-Python יש גם את לולאת ה-while הרגילה, והצהרות *break* ו-*continue* פועלות כמו ב-C++ וב-Java, ומשנה את מסלול הלולאה הפנימית ביותר. לולאות ה-for/in שלמעלה פותרות את המקרה הנפוץ של איטרציה על כל רכיב ברשימה, אבל לולאת ה-while נותנת לכם שליטה מלאה על מספרי האינדקס. לפניכם לולאת זמן שנגישה לכל רכיב שלישי ברשימה:

  ## Access every 3rd element in a list
  i = 0
  while i < len(a):
    print(a[i])
    i = i + 3

הצגת רשימה של שיטות

ריכזנו כאן כמה שיטות נפוצות אחרות ליצירת רשימות.

  • list.append(elem) – הוספת רכיב יחיד לסוף הרשימה. שגיאה נפוצה: הפונקציה לא מחזירה את הרשימה החדשה, אלא רק משנה את הרשימה המקורית.
  • list.insert(index, elem) – הוספת הרכיב לאינדקס שצוין, והזזת הרכיבים שמימין.
  • list.extend(list2) מוסיף את הרכיבים ברשימה 2 לסוף הרשימה. השימוש ב-+ או ב-+= ברשימה דומה לשימוש ב-extend().
  • list.index(elem) – מחפשת את הרכיב הנתון מתחילת הרשימה ומחזירה את האינדקס שלו. אם האלמנט לא מופיע, הפונקציה מחזירה שגיאת ValueError (כדי לבדוק בלי שגיאת ValueError, משתמשים ב-"in").
  • list.remove(elem) – חיפוש המופע הראשון של הרכיב הנתון והסרתו (מבצע ValueError אם הוא לא קיים)
  • list.sort() – ממיינים את הרשימה במקום (לא מחזירים אותה). (מומלץ להשתמש בפונקציה sorted()‎ שמופיעה בהמשך).
  • list.reverse() – הופכת את הרשימה במקומה (לא מחזירה אותה)
  • list.pop(index) – הסרה והחזרה של האלמנט באינדקס הנתון. הפונקציה מחזירה את הרכיב הימני ביותר אם לא מצוין אינדקס (כמעט ההפך מ-append()).

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

  list = ['larry', 'curly', 'moe']
  list.append('shemp')         ## append elem at end
  list.insert(0, 'xxx')        ## insert elem at index 0
  list.extend(['yyy', 'zzz'])  ## add list of elems at end
  print(list)  ## ['xxx', 'larry', 'curly', 'moe', 'shemp', 'yyy', 'zzz']
  print(list.index('curly'))    ## 2

  list.remove('curly')         ## search and remove that element
  list.pop(1)                  ## removes and returns 'larry'
  print(list)  ## ['xxx', 'moe', 'shemp', 'yyy', 'zzz']

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

  list = [1, 2, 3]
  print(list.append(4))   ## NO, does not work, append() returns None
  ## Correct pattern:
  list.append(4)
  print(list)  ## [1, 2, 3, 4]

יצירת רשימה

דפוס נפוץ אחד הוא להתחיל רשימה כרשימה ריקה [], ואז להשתמש ב-append()‎ או ב-extend()‎ כדי להוסיף אליה רכיבים:

  list = []          ## Start as the empty list
  list.append('a')   ## Use append() to add elements
  list.append('b')

הצגת רשימה של פרוסות

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

  list = ['a', 'b', 'c', 'd']
  print(list[1:-1])   ## ['b', 'c']
  list[0:2] = 'z'    ## replace ['a', 'b'] with ['z']
  print(list)         ## ['z', 'c', 'd']

תרגול: list1.py

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