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:keysresets the internal iterator shared witheachandvalues. This is the idiomatic reset — callkeys %hin void context specifically to discard any partialeachwalk:keys %h; # reset iterator, no list built while (my ($k, $v) = each %h) { ... }
Without this reset, a prior
eachthat exited early leaves the iterator mid-hash and the nexteachcall 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,
0in scalar context. No warning, no special case to code around.require v5.12for arrays:keys @arrayis a syntax error on perls older than 5.12. Putuse 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 %horder. 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
keysoutput and expect it to round-trip on a different Perl.Deleting during iteration: safe only for the key most recently returned by
eachorkeys. Deleting a different key may cause other keys to be visited twice or skipped.Lvalue
keyson arrays is a syntax error:keys(@a) = 100is not valid. The bucket-preallocation form works on hashes only.Lvalue
keyscannot shrink:keys(%h) = 10on a hash that already has 1024 buckets has no effect.%h = ()clears the contents but preserves the bucket count;undef %hfrees the buckets.Memory cost of the list form:
keys %hin list context materialises every key as a fresh SV. For a million-entry hash that is a million allocations plus the returned list. Iterate witheachorwhile (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 tiedkeysmay 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 %hin constant time; a tied class has to implementSCALARexplicitly to avoid a full walk.Scalar
keyson an array equalsscalar @array: both return the element count. Preferscalar @arrayfor clarity unless the surrounding code is already phrased inkeys/values/eachterms.
Differences from upstream#
Fully compatible with upstream Perl 5.42.
See also#
values— companion list of the values in the same order askeys; returns aliases, not copieseach— streaming(key, value)pair walk sharing the same iterator thatkeysresetsexists— test whether a specific key is present without building the full key listdelete— remove a key; safe mid-iteration only for the most recently returned keysort— impose a deterministic order on the arbitrary sequencekeysreturnsscalar— force scalar context to get the count without materialising the key list