Arrays · Hashes

keys#

List all keys of a hash, or all indices of an array.

keys is the introspection primitive for associative and indexed containers. Given %HASH it returns the hash’s keys; given @ARRAY (from Perl 5.12 onward) it returns the array’s indices 0 .. $#ARRAY. The list is what you iterate over, count, sort, or feed to another list-consuming operator. keys is also the idiomatic way to reset the iterator that each walks.

Synopsis#

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

What you get back#

In list context, a list of every key currently in %HASH, or every valid index of @ARRAY. In scalar context, the count — without building the list — so scalar keys %h is the cheap way to ask “how many entries?”

Hash keys are returned in an arbitrary order. The order is stable for a given unmodified hash — keys, values, and each all walk it in the same sequence — but it is not the insertion order, not sorted, and deliberately randomised per hash to defeat algorithmic complexity attacks (see perlsec). Any insertion or deletion may reshuffle. The one documented exception: deleting the key most recently returned by each or keys does not perturb the remaining order.

Array indices, by contrast, come back lowest-first: (0, 1, 2, …, $#ARRAY).

The returned hash keys are copies. Modifying an element of the returned list does not modify the hash. Compare values, which returns aliases.

Global state it touches#

  • Iterator of %HASH / @ARRAY: keys resets the internal iterator shared with each and values. This is the idiomatic reset — call keys %h in void context specifically to discard any partial each walk:

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

    Without this reset, a prior each that exited early leaves the iterator mid-hash and the next each call resumes there.

Examples#

Iterate all keys in an arbitrary order:

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

Iterate in a deterministic order by running the keys through sort:

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

Iterate in insertion order by tracking keys separately — hashes themselves do not remember insertion order:

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)
}

Count entries without materialising the list:

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

Preallocate buckets when you know the hash will grow large. The assignment is a size hint, rounded up to the next power of two:

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

Walk an array by index — useful when you need both the index and the element together:

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

Sort a hash by value, descending numeric:

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

Edge cases#

  • Empty hash or array: returns the empty list in list context, 0 in scalar context. No warning, no special case to code around.

  • require v5.12 for arrays: keys @array is a syntax error on perls older than 5.12. Put use v5.12; at the top of files that use the array form if portability to ancient perls matters.

  • Hash order is not reproducible across runs: Perl randomises hash seeding at startup. Never build a test, cache key, or file format that assumes a particular keys %h order. Sort if you need determinism.

  • Hash order is not stable across Perl versions: the randomised order within a run is stable; the algorithm itself is not guaranteed between releases. Do not pickle keys output and expect it to round-trip on a different Perl.

  • Deleting during iteration: safe only for the key most recently returned by each or keys. Deleting a different key may cause other keys to be visited twice or skipped.

  • Lvalue keys on arrays is a syntax error: keys(@a) = 100 is not valid. The bucket-preallocation form works on hashes only.

  • Lvalue keys cannot shrink: keys(%h) = 10 on a hash that already has 1024 buckets has no effect. %h = () clears the contents but preserves the bucket count; undef %h frees the buckets.

  • Memory cost of the list form: keys %h in list context materialises every key as a fresh SV. For a million-entry hash that is a million allocations plus the returned list. Iterate with each or while (my ($k, $v) = each %h) when you want streaming access without the memory spike.

  • Tied hashes: dispatch through FIRSTKEY / NEXTKEY. Order and side effects are whatever the tie class provides. In particular, tied hashes may reshuffle on insertion in ways ordinary hashes do not, and a tied keys may be expensive if the backing store is remote.

  • Scalar context on a tied hash: may or may not be O(1). Ordinary hashes answer scalar keys %h in constant time; a tied class has to implement SCALAR explicitly to avoid a full walk.

  • Scalar keys on an array equals scalar @array: both return the element count. Prefer scalar @array for clarity unless the surrounding code is already phrased in keys/values/each terms.

Differences from upstream#

Fully compatible with upstream Perl 5.42.

See also#

  • values — companion list of the values in the same order as keys; returns aliases, not copies

  • each — streaming (key, value) pair walk sharing the same iterator that keys resets

  • exists — test whether a specific key is present without building the full key list

  • delete — remove a key; safe mid-iteration only for the most recently returned key

  • sort — impose a deterministic order on the arbitrary sequence keys returns

  • scalar — force scalar context to get the count without materialising the key list