map#
החלת בלוק או ביטוי על כל איבר של רשימה והחזרת התוצאות בצורה משוטחת.
map מעריך את BLOCK (או EXPR) פעם אחת לכל איבר של LIST, כאשר $_ משמש ככינוי לאותו איבר, ואוסף את כל מה שכל הערכה מחזירה לרשימה משוטחת אחת. מכיוון שכל הערכה עשויה להניב אפס, אחד או הרבה ערכים, אורך הפלט אינו תלוי באורך הקלט - אותו שיטוח הוא העניין של map. בהקשר רשימה map מחזיר את הרשימה שנוצרה; בהקשר סקלר הוא מחזיר את מספר האיברים הכולל.
תקציר#
my @out = map { BLOCK } LIST; # block form
my @out = map EXPR, LIST; # expression form
my @out = map { f($_) } grep { ... } sort LIST; # chained
מה מקבלים בחזרה#
רשימה משוטחת אחת הנבנית מצירוף ערכי ההחזרה של כל הערכה, בסדר הקלט:
החזרת ערך אחד לכל קלט ← טרנספורמציה (אותו אורך בפלט).
החזרת רשימה לכל קלט ← הרחבה של 1-ל-N (פלט ארוך יותר).
החזרת הרשימה הריקה
()← דילוג על קלט זה (פלט קצר יותר; האידיוםmap-כ־filter).
בהקשר סקלר, ערך ההחזרה הוא מספר האיברים שנוצרו, לא הפניה ולא בוליאני. השמת התוצאה ל־האש מוגדרת היטב: הרשימה המשוטחת נצרכת כזוגות מפתח/ערך מתחלפים.
my @doubled = map { $_ * 2 } 1 .. 4; # (2, 4, 6, 8)
my @words = map { split /\s+/, $_ } @lines; # 1-to-N
my @kept = map { $_ > 0 ? $_ : () } @nums; # filter
my $count = map { $_ * $_ } @nums; # scalar ctx
מצב גלובלי#
$_ משמש ככינוי לכל איבר של LIST, לא מועתק. שינוי של $_ בתוך הבלוק משנה את איבר המקור. זה לפעמים שימושי אך בדרך־כלל foot-gun - יש לפנות ללולאת foreach פשוטה כשמתכוונים לשנות במקום.
my @v = (1, 2, 3);
my @r = map { $_ *= 10; $_ } @v;
# @v is now (10, 20, 30) - the source was mutated
כינוי ללא־משתנה (ליטרל, ערך החזרה של פונקציה, איבר hash-slice שעדיין לא קיים) ולאחר מכן השמה ל־$_ נכשלים בזמן ריצה עם Modification of a read-only value. ראו $_.
map גם מבצע localise ל־$_ סביב הקריאה, כך ש־$_ חיצוני הנראה לקורא משוחזר כאשר map מחזיר.
דוגמאות#
טרנספורמציה - להפוך כל מילה לאותיות גדולות:
my @upper = map { uc } @words;
הרחבה 1-ל-N - פיצול כל שורה על רווח לבן לטוקנים שלה:
my @tokens = map { split /\s+/ } @lines;
אידיום filter - שמירה רק על ערכים אמיתיים מטרנספורמטיביים:
my @positives = map { $_ > 0 ? $_ : () } @numbers;
בניית האש מרשימה - כל הערכה מחזירה רשימה בת שני איברים:
my %seen = map { $_ => 1 } @keys;
my %idx = map { ($keys[$_] => $_) } 0 .. $#keys;
שרשור מורכב - מיון, סינון, טרנספורמציה. map, grep, ו־sort לוקחים כולם LIST מימין, ולכן הם מצטרפים מימין־לשמאל:
my @top = map { "$_->{name}: $_->{score}" }
sort { $b->{score} <=> $a->{score} }
grep { $_->{score} >= 50 }
@records;
שיטוח מבנה - כל קלט תורם מספר משתנה של פלטים:
my @leaves = map { ref($_) eq 'ARRAY' ? @$_ : $_ } @mixed;
זיווג עם אינדקס באמצעות List::Util::pairs או משתנה אינדקס מפורש - map עצמו אינו חושף כזה:
my @numbered = do {
my $i = 0;
map { sprintf "%d. %s", ++$i, $_ } @items;
};
מקרי קצה#
$_משמש ככינוי, לא מועתק. השמה ל־$_כותבת בחזרה למקור. אם איבר המקור הוא קריאה־בלבד (קבוע, ערך החזרה של קריאת פונקציה ששוטחה לתוךLIST), ההשמה מעלהModification of a read-only value. יש להתייחס ל־$_כקלט־בלבד אלא אם רוצים במפורש את תופעת הלוואי.mapאינו לולאה.last,next,redo, ותוויות לולאה אינם חלים עלmap. הם מתייחסים ללולאה האמיתית העוטפת ויתנהגו בהתאם - בדרך־כלל לא מה שהמחבר התכוון. יש להשתמש ב־foreachכשנדרשת זרימת בקרת־לולאה.הקשר void מנוטרל.
map { ... } LIST;כשהתוצאה מושלכת מנפיק אזהרהUseless use of map in void contextתחתuse warnings. כשרוצים את תופעות הלוואי, לא את הרשימה, יש לכתובforeach.עמימות מפענח בין
BLOCKל־EXPR.{מתחיל גם בלוק וגם בנאי של הפניית האש.map { ... } LISTו־map { ... }, LISTנראים זהים למפענח בסוגריים הפותחים; Perl מנחש על־סמך מה שהוא מוצא לאחר־מכן. בלוק שמתחיל במה שנראה כמפתח האש בתוספת=>עשוי במיוחד להתפענח שגוי:my %h = map { "\L$_" => 1 } @a; # guessed EXPR, wrong my %h = map { +"\L$_" => 1 } @a; # unary + forces BLOCK my %h = map {; "\L$_" => 1 } @a; # leading ; forces BLOCK my %h = map { ($_, 1) } @a; # parens - unambiguous my %h = map { lc($_) => 1 } @a; # function call - unambiguous
כדי להחזיר האש אנונימי לכל איבר, יש לאלץ את בנאי ה־hash-ref עם
+{:my @hashes = map +{ lc($_) => 1 }, @array;
הסדר יציב.
mapמעריך משמאל־לימין ומצרף תוצאות משמאל־לימין. הרשימה שנוצרת שומרת את סדר הקלט, כאשר תרומת כל קלט מופיעה ברצף.LISTריקה.mapמעריך את הבלוק אפס פעמים ומחזיר את הרשימה הריקה. הבלוק אינו מוערך עבור תופעות הלוואי שלו.mapמקונן.mapפנימי רואה את$_שלו; ה־$_החיצוני מוסתר למשך ההערכה הפנימית. יש ללכוד את הערך החיצוני קודם אם שניהם נחוצים:my @pairs = map { my $outer = $_; map { [$outer, $_] } @inner } @outer;
הבדלים מ־upstream#
תואם מלא ל־upstream Perl 5.42.
ראו גם#
grep- אותה צורה כמוmap, אך שומר איברים שהבלוק אמת עבורם במקום להמיר אותם; מתחבר באופן טבעי עםmapו־sortsort- ממיין רשימה; נהוג להרכיב אותו עםmapבאמצעות הטרנספורם השוורצי (map←sort←map)for/foreach- בשימוש כשרוצים איטרציה עבור תופעות לוואי, שינוי המקור, או בקרת־לולאה (last/next/redo)x- אופרטור חזרה על רשימה; אורתוגונלי ל־mapאך משמש לעיתים קרובות לבניית ה־LISTש־mapצורךList::Util::reduce- קיפול רשימה לערך יחיד; להשתמש בו כאשר התוצאה אינה רשימה אלא צבירה (סכום, מקסימום, התאמה ראשונה)$_- כינוי האיבר בתוך הבלוק; קריאה־בלבד כאשר איבר המקור הוא ליטרל או ערך החזרה של פונקציה