מערכים#
מערך הוא רצף מסודר של סקלרים הממופתח במספרים שלמים. ה־sigil הוא @ עבור המערך כולו ועבור פרוסות (שהן רשימות); $ עבור אלמנט יחיד (שהוא סקלר אחד). ה־sigil המוביל אומר לכם את טיפוס התוצאה, לא את המכל.
my @days = ('Mon', 'Tue', 'Wed', 'Thu', 'Fri');
@days # the whole array (5 elements)
$days[0] # the first element - a single scalar
@days[1, 3] # a slice - a list of two scalars
$#days # the last valid index - here, 4
scalar @days # the length - here, 5
אינדקסים מתחילים ב־0. אינדקסים שליליים נספרים מהסוף ($days[-1] הוא 'Fri').
אורך: $#arr מול scalar @arr#
שתי כמויות קשורות, המשמשות למשימות שונות:
$#days # last valid index - 4
scalar @days # number of elements - 5
$#days + 1 # equivalent to scalar @days
השמה ל־$#arr משנה את גודל המערך. כיווץ הורס את האלמנטים שמעבר לקצה החדש; הגדלה ממלאת אותם ב־undef:
my @a = (1, 2, 3, 4, 5);
$#a = 2; # @a is now (1, 2, 3) - length 3
$#a = 5; # @a is now (1, 2, 3, undef, undef, undef)
$#a = -1; # @a is now () - empty
הצורה @a = () היא השמת המערך־הריק הניבית; $#a = -1 שקולה ולעיתים ברורה יותר כאשר הכוונה היא ”shrink to nothing without changing the variable’s identity“.
גישה לאלמנטים#
my $first = $days[0]; # 'Mon'
my $last = $days[-1]; # 'Fri'
my $last = $days[$#days]; # same; redundant but explicit
$days[2] = 'Wednesday'; # set
$days[10] = 'Sunday'; # auto-extends; $days[5..9] become undef
קריאה מעבר לקצה מחזירה undef (ללא אזהרה - קריאה מחוץ לטווח היא אי־אירוע). כתיבה מעבר לקצה מגדילה את המערך; החריצים שביניהם הופכים ל־undef.
my @a;
$a[5] = 'fifth';
# @a is now (undef, undef, undef, undef, undef, 'fifth')
print scalar @a; # 6
קריאת אינדקס שלילי רחוק יותר לאחור מההתחלה היא שגיאה קטלנית:
my @a = (1, 2, 3);
$a[-10]; # FATAL: Modification of non-creatable
# array value attempted
פעולות המערך־כולו#
push @arr, $value; # append at end - returns new length
my $v = pop @arr; # remove from end - returns removed element
my $v = shift @arr; # remove from start - returns removed element
unshift @arr, $value; # prepend - returns new length
splice @arr, $offset, $len, @replacement; # general remove/insert
shift ו־unshift הם O(n) משום שהם ממספרים מחדש כל אלמנט נותר; push ו־pop הם O(1) ממוצע. עבור עומסי עבודה בצורת תור שבהם זה חשוב, העדיפו push/shift בקצה הקצר או השתמשו ב־deque מ־List::Util (שיש לו רדוקציות, לא deque).
splice הוא אולר השוויצרי: הסירו מקטע של אלמנטים, הכניסו מקטע במקומם, החזירו את מה שהוסר:
my @arr = (1, 2, 3, 4, 5);
my @gone = splice @arr, 1, 2; # @gone = (2, 3); @arr = (1, 4, 5)
splice @arr, 1, 0, ('a', 'b'); # insert at offset 1, no removal
# @arr = (1, 'a', 'b', 4, 5)
$offset שלילי נספר מהסוף. $len שלילי שומר על מספר זה של אלמנטים גוררים:
splice @arr, -1; # remove just the last element
splice @arr, 0, -2; # remove all but the last two
פרוסות#
פרוסה מחלצת (או משימה ל) כמה אלמנטים בבת אחת. האינדקסים מגיעים מרשימה:
my @arr = ('a', 'b', 'c', 'd', 'e');
my @subset = @arr[0, 2, 4]; # ('a', 'c', 'e')
my @middle = @arr[1..3]; # ('b', 'c', 'd')
my @last3 = @arr[-3..-1]; # ('c', 'd', 'e')
my @rev = @arr[reverse 0..$#arr]; # ('e', 'd', 'c', 'b', 'a')
@arr[1, 3] = ('B', 'D'); # set positions 1 and 3
@arr[1, 3] = @arr[3, 1]; # swap two elements (no temp)
פרוסת מפתח/ערך עם % מחזירה זוגות אינדקס/ערך (Perl 5.20+):
my @arr = ('a', 'b', 'c', 'd', 'e');
my %picked = %arr[1, 3]; # (1 => 'b', 3 => 'd')
זוהי הצורה הנכונה כאשר אתם זקוקים גם לאינדקס וגם לערך של אלמנטים נבחרים. ראו מנוי עבור מטריצת שתים־עשרה־הדרכים של צורות פרוסה.
הקשר רשימה מול הקשר סקלר#
מערך בהקשר רשימה מניב את האלמנטים שלו; בהקשר סקלר, הוא מניב את אורכו:
my @arr = (10, 20, 30);
my @copy = @arr; # list context - three elements
my $length = @arr; # scalar context - 3
print "got @arr\n"; # list context inside "" - "got 10 20 30"
print "got " . @arr . "\n"; # scalar context (concat) - "got 3"
ההבחנה היא מלכודת Perl הנפוצה ביותר. שני כללי אצבע:
בתוך מחרוזות במרכאות כפולות, מערכים משובצים כאלמנטים שלהם המחוברים על־ידי
$"(רווח יחיד כברירת מחדל). ראו שיבוץ.בהקשר אופרטור מספרי או מחרוזת (
+,., השוואה), מערך מניב את אורכו.
אלצו הקשר סקלר עם scalar כאשר מיקום הביטוי דו־משמעי אחרת:
print "got " . scalar(@arr) . " items\n"; # "got 3 items"
print "got @arr items\n"; # "got 10 20 30 items" - different!
השמת רשימה וניב הספירה#
השמת רשימה למערך הופכת את המערך ארוך בדיוק כך:
my @arr = (1, 2, 3);
@arr = (10, 20); # @arr is now (10, 20)
@arr = (); # @arr is now empty
השמת רשימה לרשימה של סקלרים מפרקת (כל עודף מושלך; החסרים הופכים ל־undef):
my ($x, $y, $z) = (1, 2, 3); # 1, 2, 3
my ($x, $y, $z) = (1, 2); # 1, 2, undef
my ($x, $y) = (1, 2, 3); # 1, 2 - '3' silently dropped
השמת רשימה בהקשר סקלר מחזירה את מספר האלמנטים בצד הימני. זהו מקור ניב הספירה:
my $count = () = $string =~ /\d+/g;
# $string =~ /\d+/g - match in list context, returns all matches
# () = LIST - list assignment to empty list
# $count = SCALAR - that assignment in scalar context = count of RHS
האמצע () = LIST הוא הטריק. בלעדיו, $count = $s =~ /\d+/g נותן בוליאני במקום ספירה.
הפניות מערך#
מערכים אינם ערכים ממדרגה ראשונה במובן שהם יכולים להיות מועברים בשם דרך שרשרת של קריאות פונקציה מבלי להשתטח לרשימה. כדי להעביר מערך מבלי להשטיח, קחו הפניה אליו:
my @items = (1, 2, 3);
my $aref = \@items; # reference to the existing @items
my $anon = [1, 2, 3]; # anonymous array reference
$aref->[0] # access through the arrow - 1
@{$aref} # fully bracketed deref - list (1, 2, 3)
@$aref # unbracketed deref - same as above
$#{$aref} # last index of dereffed array
scalar @$aref # length
ראו הפניות לתמונה המלאה.
דוגמה אמיתית: בניית היסטוגרמה של אורכי מילים#
my @words = qw(the quick brown fox jumps over the lazy dog);
my @hist;
$hist[length $_]++ for @words;
for my $len (1 .. $#hist) {
next unless $hist[$len];
printf "%2d-letter words: %d\n", $len, $hist[$len];
}
# 3-letter words: 4
# 4-letter words: 2
# 5-letter words: 3
שימו לב ש־$hist[length $_]++ עושה autovivify (יוצר) לחריץ כשזו המילה הראשונה באורך זה. קריאה מ־$hist[7] מאוחר יותר מחזירה undef, ש־++ משמח להגדיל - אך next unless $hist[$len] מדלג על הפער לפני ההדפסה.
ראו גם#
האשים - כאשר האינדקס הוא מחרוזת, לא מספר שלם.
הפניות - העברת מערכים מבלי להשטיח.
הקשר - סיפור הרשימה־מול־סקלר מורחב.
שיבוץ - כיצד מערכים מופיעים בתוך
"".אופרטורי מנוי ופרוסה - משפחת הסוגריים־המרובעים־והמסולסלים בפירוט.
אופרטור הטווח
..- המקור הנפוץ ביותר לרשימות אינדקס של פרוסה.scalar- מאלץ הקשר סקלר (אורך).