מערכים · האשים

keys#

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

keys הוא הפרימיטיב לאינטרוספקציה של מכלים אסוציאטיביים ואינדקסיים. בהינתן %HASH הוא מחזיר את מפתחות ההאש; בהינתן @ARRAY (מ־Perl 5.12 ואילך) הוא מחזיר את אינדקסי המערך 0 .. $#ARRAY. הרשימה היא מה שעוברים עליו, סופרים, ממיינים, או מזינים לאופרטור צורך־רשימה אחר. keys הוא גם הדרך האידיומטית לאפס את האיטרטור ש־each עובר עליו.

תקציר#

my @k = keys %h;
my @i = keys @a;
my $n = keys %h;        # scalar context: count
keys(%h) = 1000;        # preallocate buckets (hash only)

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

בהקשר רשימה, רשימה של כל מפתח הנמצא כעת ב־%HASH, או כל אינדקס תקף של @ARRAY. בהקשר סקלר, הספירה - בלי לבנות את הרשימה - כך ש־scalar keys %h הוא הדרך הזולה לשאול ״כמה רשומות?״

מפתחות ההאש מוחזרים בסדר שרירותי. הסדר יציב להאש לא־משונה נתון - keys, values, ו־each כולם עוברים עליו באותו רצף - אך אינו סדר ההכנסה, אינו ממוין, ומעורבל במכוון לכל האש כדי לסכל התקפות סיבוכיות אלגוריתמיות (ראו perlsec). כל הכנסה או מחיקה עלולה לערבב מחדש. החריגה המתועדת היחידה: מחיקת המפתח האחרון שהוחזר על־ידי each או keys אינה משבשת את הסדר הנותר.

אינדקסי מערך, לעומת זאת, חוזרים מהנמוך־ביותר־ראשון: (0, 1, 2, …, $#ARRAY).

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

מצב גלובלי שהוא נוגע בו#

  • איטרטור של %HASH / @ARRAY: keys מאפס את האיטרטור הפנימי המשותף עם each ו־values. זהו האיפוס האידיומטי - יש לקרוא ל־keys %h בהקשר void במיוחד כדי להשליך כל סריקת each חלקית:

    keys %h;                # reset iterator, no list built
    while (my ($k, $v) = each %h) { ... }
    

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

דוגמאות#

לעבור על כל המפתחות בסדר שרירותי:

my %h = (apple => 1, pear => 2, plum => 3);
for my $k (keys %h) {
    print "$k => $h{$k}\n";
}

לעבור בסדר דטרמיניסטי על־ידי הרצת המפתחות דרך sort:

for my $k (sort keys %h) {
    print "$k => $h{$k}\n";     # apple, pear, plum
}

לעבור בסדר ההכנסה על־ידי מעקב נפרד אחר המפתחות - ההאשים עצמם אינם זוכרים את סדר ההכנסה:

my %h;
my @order;
for my $pair (["apple", 1], ["pear", 2], ["plum", 3]) {
    my ($k, $v) = @$pair;
    push @order, $k unless exists $h{$k};
    $h{$k} = $v;
}
for my $k (@order) {
    print "$k => $h{$k}\n";     # apple, pear, plum (insertion)
}

ספירת רשומות בלי לחומר את הרשימה:

my $n = keys %h;                # scalar context, O(1)
print "hash has $n entries\n";

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

my %big;
keys(%big) = 10_000;            # allocates 16384 buckets
$big{$_} = 1 for 1 .. 10_000;   # no rehash churn during fill

מעבר על מערך לפי אינדקס - שימושי כאשר נדרשים גם האינדקס וגם האלמנט יחד:

my @a = ("zero", "one", "two");
for my $i (keys @a) {
    print "$i: $a[$i]\n";
}

מיון האש לפי ערך, מספרי יורד:

for my $k (sort { $h{$b} <=> $h{$a} } keys %h) {
    printf "%4d %s\n", $h{$k}, $k;
}

מקרי קצה#

  • האש או מערך ריק: מחזיר את הרשימה הריקה בהקשר רשימה, 0 בהקשר סקלר. ללא אזהרה, ללא מקרה מיוחד לעקוף בקוד.

  • require v5.12 עבור מערכים: keys @array היא שגיאת תחביר ב־perls ישנים מ־5.12. יש לשים use v5.12; בראש קבצים המשתמשים בצורת המערך אם ניידות ל־perls עתיקים חשובה.

  • סדר ההאש אינו ניתן לשחזור בין ריצות: Perl מערבלת את זרעי ההאש בעת ההפעלה. אין לבנות בדיקה, מפתח cache, או פורמט קובץ שמניח סדר מסוים של keys %h. יש למיין אם נדרש דטרמיניזם.

  • סדר ההאש אינו יציב בין גרסאות Perl: הסדר המעורבל בתוך ריצה יציב; האלגוריתם עצמו אינו מובטח בין מהדורות. אין לסריאליז את פלט keys ולצפות לנסיעה חזור על Perl אחר.

  • מחיקה במהלך איטרציה: בטוחה רק עבור המפתח האחרון שהוחזר על־ידי each או keys. מחיקת מפתח אחר עלולה לגרום למפתחות אחרים להיות מבוקרים פעמיים או מדולגים.

  • keys כ־lvalue על מערכים היא שגיאת תחביר: keys(@a) = 100 אינה חוקית. צורת הקצאה־מראש־של־דליים עובדת על האשים בלבד.

  • keys כ־lvalue אינה יכולה להקטין: keys(%h) = 10 על האש שכבר יש לו 1024 דליים אינה משפיעה. %h = () מנקה את התוכן אך משמרת את ספירת הדליים; undef %h משחרר את הדליים.

  • עלות זיכרון של צורת הרשימה: keys %h בהקשר רשימה מחומר כל מפתח כ־SV רענן. עבור האש של מיליון רשומות זה מיליון הקצאות ועוד הרשימה המוחזרת. יש לעבור עם each או while (my ($k, $v) = each %h) כאשר נדרשת גישה הזרמתית בלי קפיצת הזיכרון.

  • האשים קשורים: הדיספאץ« עובר דרך FIRSTKEY / NEXTKEY. הסדר ותופעות הלוואי הם כל מה שמחלקת ה־tie מספקת. בפרט, האשים קשורים עלולים לערבב מחדש בהכנסה בדרכים שהאשים רגילים אינם, ו־keys קשור עלול להיות יקר אם האחסון התומך מרוחק.

  • הקשר סקלר על האש קשור: עשוי להיות O(1) או לא. האשים רגילים עונים על scalar keys %h בזמן קבוע; מחלקה קשורה חייבת לממש SCALAR במפורש כדי להימנע מסריקה מלאה.

  • keys סקלרי על מערך שווה ל־scalar @array: שניהם מחזירים את ספירת האלמנטים. מומלץ scalar @array למען בהירות אלא אם הקוד הסובב כבר מנוסח במונחי keys/values/each.

הבדלים מ־upstream#

תואם מלא ל־upstream Perl 5.42.

ראו גם#

  • values - רשימה משלימה של הערכים באותו סדר כמו keys; מחזיר כינויים, לא עותקים

  • each - סריקה הזרמתית של זוגות (מפתח, ערך) המשתפת את אותו איטרטור ש־keys מאפס

  • exists - בדיקה האם מפתח מסוים נוכח בלי לבנות את רשימת המפתחות המלאה

  • delete - להסיר מפתח; בטוח באמצע איטרציה רק עבור המפתח האחרון שהוחזר

  • sort - להטיל סדר דטרמיניסטי על הרצף השרירותי ש־keys מחזיר

  • scalar - לאלץ הקשר סקלר כדי לקבל את הספירה בלי לחומר את רשימת המפתחות