מיון ב-Python

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

  a = [5, 1, 4, 3]
  print(sorted(a))  ## [1, 3, 4, 5]
  print(a)  ## [5, 1, 4, 3]

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

אפשר להתאים אישית את הפונקציה Sorted() באמצעות ארגומנטים אופציונליים. הארגומנט האופציונלי הפוך (called() ) מהפונקציה true=True, לדוגמה. למיין(list, newer=True), הפונקציה ממיינת אחורה.

  strs = ['aa', 'BB', 'zz', 'CC']
  print(sorted(strs))  ## ['BB', 'CC', 'aa', 'zz'] (case sensitive)
  print(sorted(strs, reverse=True))   ## ['zz', 'aa', 'CC', 'BB']

מיון מותאם אישית עם מקש=

כדי לבצע מיון מותאם אישית מורכב יותר, הפונקציה listed() משתמשת ב-"key=" ציון 'מפתח' שמשנה כל רכיב לפני ההשוואה. פונקציית המפתח מקבלת ערך 1 ומחזירה ערך 1, ואת הערך שמוחזר במאפיין 'proxy'. משמש להשוואות בתוך המיון.

לדוגמה, כשמזינים את רשימת מחרוזות, כשמציינים את הפונקציה key=len (הפונקציה len() ) ממיינת את המחרוזות לפי אורך, מהקצר ביותר ארוך ביותר. המיון קורא לפונקציה len() עבור כל מחרוזת כדי לקבל את הרשימה של ערכי האורך של שרת ה-proxy, ולאחר מכן ממיין לפי ערכי ה-proxy האלה.

  strs = ['ccc', 'aaaa', 'd', 'bb']
  print(sorted(strs, key=len))  ## ['d', 'bb', 'ccc', 'aaaa']

השיחות ממוינות עם key=len

דוגמה נוספת, ציון "str.lower" מכיוון שפונקציית המפתח היא דרך לאלץ את המיון להתייחס לאותיות רישיות וקטנות באותו אופן:

  ## "key" argument specifying str.lower function to use for sorting
  print(sorted(strs, key=str.lower))  ## ['aa', 'BB', 'CC', 'zz']

אפשר גם להעביר את MyFn שלכם כפונקציית המפתח, למשל:

  ## Say we have a list of strings we want to sort by the last letter of the string.
  strs = ['xc', 'zb', 'yd' ,'wa']

  ## Write a little function that takes a string, and returns its last letter.
  ## This will be the key function (takes in 1 value, returns 1 value).
  def MyFn(s):
    return s[-1]

  ## Now pass key=MyFn to sorted() to sort by the last letter:
  print(sorted(strs, key=MyFn))  ## ['wa', 'zb', 'xc', 'yd']

כדי לבצע מיון מורכב יותר, כמו מיון לפי שם משפחה ואחר כך לפי שם פרטי, אפשר להשתמש בפונקציות itemgetter או attdgetter כמו:

  from operator import itemgetter

  # (first name, last name, score) tuples
  grade = [('Freddy', 'Frank', 3), ('Anil', 'Frank', 100), ('Anil', 'Wang', 24)]
  sorted(grade, key=itemgetter(1,0))
  # [('Anil', 'Frank', 100), ('Freddy', 'Frank', 3), ('Anil', 'Wang', 24)]

  sorted(grade, key=itemgetter(0,-1))
  #[('Anil', 'Wang', 24), ('Anil', 'Frank', 100), ('Freddy', 'Frank', 3)]

שיטת מיון

כחלופה ל-sorted(), שיטת המיון() ברשימה ממיינת את הרשימה לסדר עולה, לדוגמה. list.sort(). שיטת המיון (() ) משנה את הרשימה הבסיסית ומחזירה None, לכן צריך להשתמש בה כך:

  alist.sort()            ## correct
  alist = blist.sort()    ## Incorrect. sort() returns None

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

קפלים

טפלון הוא קבוצה של אלמנטים בגודל קבוע, כמו קואורדינטה (x, y). צבעוניות הן כמו רשימות, אבל הן לא ניתנות לשינוי וגודלן לא משתנה (הצורות לא ניתנות לשינוי בהחלטה כי אחד מהרכיבים המוכלים יכול להיות ניתן לשינוי). אפרוחים משחקים סוג של 'מבנה' ב-Python – דרך נוחה להעביר מערך קטן של ערכים הגיוניים וקבועים. פונקציה שצריכה להחזיר ערכים מרובים יכולה פשוט להחזיר מספר רב של ערכים. לדוגמה, אם אני רוצה לקבל רשימה של קואורדינטות תלת-ממדיות, הייצוג הטבעי של python יהיה רשימה של טפלים, כאשר כל טפלון הוא בגודל 3 שמכיל קבוצה אחת (x, y, z).

כדי ליצור tuple, פשוט צריך לרשום את הערכים בסוגריים ולהפריד ביניהם באמצעות פסיקים. השדה "ריק" tuple הוא רק סוגריים ריקים. הגישה לרכיבים ב-tuple פועלת בדיוק כמו רשימה – len() , [ ], for, in וכו'.

  tuple = (1, 2, 'hi')
  print(len(tuple))  ## 3
  print(tuple[2])    ## hi
  tuple[2] = 'bye'  ## NO, tuples cannot be changed
  tuple = (1, 2, 'bye')  ## this works

כדי ליצור גלימה בגודל 1, צריך להוסיף פסיק אחרי האלמנט הבודד.

  tuple = ('hi',)   ## size-1 tuple

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

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

  (x, y, z) = (42, 13, "hike")
  print(z)  ## hike
  (err_string, err_code) = Foo()  ## Foo() returns a length-2 tuple

הצגת רשימה של שילובים (אופציונלי)

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

  nums = [1, 2, 3, 4]

  squares = [ n * n for n in nums ]   ## [1, 4, 9, 16]

התחביר הוא [ expr for var in list ] – ה-for var in list נראה כמו לולאה רגילה, אבל בלי נקודתיים (:). ה-expr שמשמאל לו מוערך פעם אחת לכל רכיב כדי לספק את הערכים לרשימה החדשה. הנה דוגמה עם מחרוזות, שבה כל מחרוזת משתנה לאותיות רישיות עם התו '!!!' מצורף:

  strs = ['hello', 'and', 'goodbye']

  shouting = [ s.upper() + '!!!' for s in strs ]
  ## ['HELLO!!!', 'AND!!!', 'GOODBYE!!!']

אפשר להוסיף בדיקת if מימין ללולאת ה-for (ללולאה) כדי לצמצם את התוצאה. בדיקת ה-if נבדקת לגבי כל רכיב, כולל רק הרכיבים שבהם הבדיקה מתקיימת.

  ## Select values <= 2
  nums = [2, 8, 1, 6]
  small = [ n for n in nums if n <= 2 ]  ## [2, 1]

  ## Select fruits containing 'a', change to upper case
  fruits = ['apple', 'cherry', 'banana', 'lemon']
  afruits = [ s.upper() for s in fruits if 'a' in s ]
  ## ['APPLE', 'BANANA']

תרגיל: list1.py

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