--- name: keys signatures: - 'keys HASH' - 'keys ARRAY' since: 5.0 status: documented categories: ["Arrays", "Hashes"] --- ```{index} single: keys; Perl built-in ``` *[Arrays](../perlfunc-by-category) · [Hashes](../perlfunc-by-category)* # 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`](each) walks. ## Synopsis ```perl 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`](values), and [`each`](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`](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`](values), which returns aliases. ## Global state it touches - **Iterator of `%HASH` / `@ARRAY`**: `keys` resets the internal iterator shared with [`each`](each) and [`values`](values). This is the idiomatic reset — call `keys %h` in void context specifically to discard any partial [`each`](each) walk: ```perl keys %h; # reset iterator, no list built while (my ($k, $v) = each %h) { ... } ``` Without this reset, a prior [`each`](each) that exited early leaves the iterator mid-hash and the next [`each`](each) call resumes there. ## Examples Iterate all keys in an arbitrary order: ```perl 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`](sort): ```perl 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: ```perl 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: ```perl 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: ```perl 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: ```perl my @a = ("zero", "one", "two"); for my $i (keys @a) { print "$i: $a[$i]\n"; } ``` Sort a hash by value, descending numeric: ```perl 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`](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`](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`](values)/[`each`](each) terms. ## Differences from upstream Fully compatible with upstream Perl 5.42. ## See also - [`values`](values) — companion list of the values in the same order as `keys`; returns aliases, not copies - [`each`](each) — streaming `(key, value)` pair walk sharing the same iterator that `keys` resets - [`exists`](exists) — test whether a specific key is present without building the full key list - [`delete`](delete) — remove a key; safe mid-iteration only for the most recently returned key - [`sort`](sort) — impose a deterministic order on the arbitrary sequence `keys` returns - [`scalar`](scalar) — force scalar context to get the count without materialising the key list