רשימות

sort#

ממיין רשימה, ומחזיר את הרשימה הממוינת.

sort לוקח רשימה ומחזיר רשימה חדשה עם האלמנטים מסודרים בסדר. ללא משווה הוא משתמש בהשוואת מחרוזות סטנדרטית. עם BLOCK או SUBNAME אתם מספקים את כלל ההשוואה כפונקצייה קטנה שנקראת עבור כל זוג אלמנטים וחייבת להחזיר ערך שלילי, אפס, או חיובי באופן ש־cmp ו־<=> עושים.

המיון יציב - אלמנטים שמשוים שווים שומרים על הסדר היחסי המקורי שלהם. האלגוריתם הוא mergesort.

תקציר#

sort LIST
sort BLOCK LIST
sort SUBNAME LIST

שלוש צורות אידיומטיות:

my @out = sort @in;                        # default: string cmp, ascending
my @out = sort { $a <=> $b } @in;          # numeric, ascending
my @out = sort by_name @in;                # named comparator sub

מה מקבלים בחזרה#

רשימה ממוינת חדשה. sort אינו משנה את הקלט במקום. כדי להחליף מערך בגרסה הממוינת שלו עליכם להשים בחזרה:

@a = sort @a;

בהקשר רשימה ההחזרה היא הרשימה הממוינת. בהקשר סקלרי ערך ההחזרה לא־מוגדר - אל תשתמשו ב־scalar sort.

הרשימה המוחזרת מכילה aliases לתוך הרשימה המקורית, בדיוק כמו משתנה אינדקס של foreach. שינוי אלמנט של התוצאה בתוך foreach, map, או grep מאוחר משנה לכן גם את האלמנט המקורי. זה כמעט אף פעם אינו מה שרוצים; התייחסו לתוצאה כקריאה־בלבד.

מצב גלובלי: $a ו־$b#

בתוך ה־BLOCK או SUBNAME של המשווה, שני האלמנטים המושווים נחשפים כגלובלים של חבילה $a ו־$b. אלה אינם פרמטרים והם אינם לקסיקליים - הם משתני חבילה אמיתיים ש־sort עושה להם localize סביב הקריאה.

  • $a ו־$b חיים בחבילה שקראה ל־sort. ב־main, זה $main::a ו־$main::b; ב־Foo, $Foo::a ו־$Foo::b.

  • לעולם אל תצהירו על my $a או my $b בכל מקום שבלוק המיון יכול לראות. $a או $b לקסיקליים מצלים על הגלובלי של החבילה; הבלוק אז משווה שני משתנים לא־קשורים והמיון מפיק בשקט זבל. תחת use warnings אינכם מקבלים אזהרה על כך.

  • אם אתם זקוקים באמת ל־$a / $b כלקסיקליים במקום אחר, התייחסו למשתני המיון בשם המלא בתוך הבלוק:

    print sort { $::a cmp $::b }         qw(A C E G B D F H);
    print sort { our $a cmp our $b }     qw(A C E G B D F H);
    
  • משווה המוגדר עם ה־prototype ($$) (או אטריבוט חתימה מקביל) מקבל את הזוג ב־@_ במקום ב־$a ו־$b. זה איטי יותר ממוסכמת $a/$b אבל מנתק את תת־השגרה מהחבילה של הקורא.

שני האלמנטים מועברים בהפניה; שינוי $a או $b בבלוק משנה את הרשימה המקורית. אל תעשו זאת.

דוגמאות#

מיון מחרוזות ברירת מחדל:

my @sorted = sort qw(banana apple cherry);
# ('apple', 'banana', 'cherry')

מספרי עולה - ברירת המחדל sort @nums תמיין את "10" לפני "2" כי ההשוואה היא לפי מחרוזת:

my @nums = sort { $a <=> $b } (10, 2, 33, 4);
# (2, 4, 10, 33)

מספרי יורד - להחליף את $a ו־$b:

my @nums = sort { $b <=> $a } (10, 2, 33, 4);
# (33, 10, 4, 2)

מיון רב־מפתחות עם שובר־שוויון. || מריץ את המשווה השני רק כאשר הראשון מחזיר 0:

my @people = sort {
    $a->{last}  cmp $b->{last}
 || $a->{first} cmp $b->{first}
} @records;

מיון מפתחות של האש לפי הערך המקושר:

my %age = (alice => 30, bob => 25, carol => 40);
my @by_age = sort { $age{$a} <=> $age{$b} } keys %age;
# ('bob', 'alice', 'carol')

טרנספורם שוורצי - כאשר מפתח המיון יקר לחישוב, חשבו אותו פעם אחת לכל אלמנט, מיינו את זוגות [key, value], ואז הסירו את המפתחות. שלושה שלבים, לקרוא מלמטה למעלה:

my @sorted =
    map  { $_->[1] }                     # 3. strip key
    sort { $a->[0] <=> $b->[0] }         # 2. sort by key
    map  { [ expensive_key($_), $_ ] }   # 1. attach key
    @input;

תת־שגרת משווה בעלת שם. תת־השגרה קוראת $a ו־$b מחבילת הקורא, אז היא חייבת להיות באותה חבילה (או להיות מקושרת ממנה):

sub by_name { $a->{name} cmp $b->{name} }

my @sorted = sort by_name @people;

משווה עם prototype - הארגומנטים מגיעים ב־@_, אז הוא עובד מכל חבילה:

sub numeric ($$) { $_[0] <=> $_[1] }

my @sorted = sort numeric @nums;

מקרי קצה#

  • $a ו־$b הם גלובלים של חבילה, לא לקסיקליים. my $a תועה בתחום שובר בשקט כל מיון באותו תחום. אם עליכם, השתמשו ב־our $a או ב־$::a בתוך הבלוק.

  • <=> מספרי, cmp מחרוזתי. שימוש בלא־נכון הוא באג המיון הנפוץ ביותר. sort { $a cmp $b } (10, 2, 33) מניב (10, 2, 33) - לקסיקוגרפי, "10" לפני "2". השתמשו ב־<=> למספרים.

  • רשימה ריקה מחזירה רשימה ריקה. sort () הוא (). אין שגיאה.

  • אלמנט בודד מוחזר ללא שינוי. אין השוואות.

  • המשווה חייב להיות עקבי. אם הוא לפעמים אומר $x < $y ולפעמים אומר את ההפך עבור אותו זוג, התוצאה לא־מוגדרת. המשווה חייב להחזיר סדר טוטלי: שלילי, אפס, או חיובי, באופן יציב, לכל קריאה.

  • NaN מרעיל את <=>. $a <=> $b מחזיר undef אם אחד מהאופרנדים הוא NaN, ש־sort אז מתייחס אליו כ־0 - שווה - נותן מיקום שרירותי. סננו תחילה:

    my @clean = sort { $a <=> $b } grep { $_ == $_ } @input;
    
  • מיון יציב. אלמנטים שווים שומרים על סדר הקלט שלהם. הסתמכו על זה למיונים רב־מעבריים (מיון לפי מפתח משני תחילה, ואז לפי מפתח ראשי). use sort 'stable' הוא ברירת המחדל וחסר־פעולה; פראגמות use sort '_mergesort' / '_qsort' הן היסטוריות ואין להן השפעה על Perl הנוכחי.

  • sort אינו במקום. sort @a אינו נוגע ב־@a. השתמשו ב־@a = sort @a כדי להחליפו. השמה לרשימת התוצאה של sort יוצרת alias בחזרה למקור, אז (sort @a)[0] = ... משנה את האלמנט הקטן ביותר של @a.

  • No loop control out of the block. last, next, redo, return, and goto LABEL do not work inside a sort comparator

    • the block is not a loop body.

  • מלכודת מפענח: מיון ערך החזרה של פונקצייה. sort לוקח LIST, אז bareword בא אחריו יכולה להיות מובנת בטעות כ־SUBNAME. למיון התוצאה של find_records(@key):

    my @out = sort { $a cmp $b } find_records @key;   # OK
    my @out = sort +find_records(@key);               # OK
    my @out = sort(find_records(@key));               # OK
    

    לשימוש ב־find_records כמשווה על @key במקום:

    my @out = sort find_records @key;                 # comparator form
    my @out = sort { find_records() } @key;           # block form
    
  • מיון מודע locale. תחת use locale (ללא ':not_characters') השוואת המחרוזות ברירת המחדל עוקבת אחר ה־collation locale הנוכחי במקום סדר נקודות הקוד.

  • משווי XSUB. אם המשווה הוא XSUB, הזוג מועבר על מחסנית הארגומנטים באופן שפונקציות XS מקבלות ארגומנטים בדרך כלל; $a ו־$b אינם נקבעים.

הבדלים מהמקור#

תאימות מלאה עם Perl 5.42 המקורי.

ראו גם#

  • reverse - היפוך רשימה; שלבו עם sort למיונים יורדים כאשר המשווה קשה להיפוך על־ידי החלפת $a ו־$b

  • map - החצי השני של הטרנספורם השוורצי; השתמשו לחיבור והסרת מפתחות מיון סביב sort

  • grep - סינון מקדים של הרשימה (למשל הסרת NaN או undef) לפני העברתה ל־sort

  • $a - האלמנט הראשון בזוג ההשוואה, ב־alias כגלובלי של חבילה למשך המיון

  • $b - האלמנט השני בזוג ההשוואה, אותם כללי משך־חיים ותיחום כמו $a

  • <=> - השוואה מספרית תלת־כיוונית; האופרטור הרגיל בתוך בלוק מיון מספרי

  • cmp - השוואת מחרוזות תלת־כיוונית; האופרטור הרגיל בתוך בלוק מיון מחרוזות