Lists

map#

Apply a block or expression to each element of a list and return the flattened results.

map evaluates BLOCK (or EXPR) once per element of LIST, with $_ aliased to that element, and collects everything each evaluation returns into a single flat list. Because each evaluation may yield zero, one, or many values, the output length is independent of the input length — that flattening is the point of map. In list context map returns the generated list; in scalar context it returns the total element count.

Synopsis#

my @out = map { BLOCK } LIST;       # block form
my @out = map EXPR, LIST;           # expression form
my @out = map { f($_) } grep { ... } sort LIST;   # chained

What you get back#

A single flat list built by concatenating the return values of each evaluation, in input order:

  • Return one value per input → transform (same length out).

  • Return a list per input → 1-to-N expansion (longer out).

  • Return the empty list () → skip this input (shorter out; map-as-filter idiom).

In scalar context the return value is the count of generated elements, not a reference and not a boolean. Assigning the result to a hash is well-defined: the flat list is consumed as alternating key/value pairs.

my @doubled = map { $_ * 2 }          1 .. 4;     # (2, 4, 6, 8)
my @words   = map { split /\s+/, $_ } @lines;     # 1-to-N
my @kept    = map { $_ > 0 ? $_ : () } @nums;     # filter
my $count   = map { $_ * $_ } @nums;              # scalar ctx

Global state#

$_ is aliased to each element of LIST, not copied. Modifying $_ inside the block modifies the source element. This is occasionally useful but usually a footgun — reach for a plain foreach loop when you mean to mutate in place.

my @v = (1, 2, 3);
my @r = map { $_ *= 10; $_ } @v;
# @v is now (10, 20, 30) — the source was mutated

Aliasing to a non-variable (a literal, a function return value, a hash-slice element that doesn’t exist yet) and then assigning to $_ fails at runtime with Modification of a read-only value. See $_.

map also localises $_ around the call, so an outer $_ visible to the caller is restored when map returns.

Examples#

Transform — uppercase every word:

my @upper = map { uc } @words;

1-to-N expansion — split each line on whitespace into its tokens:

my @tokens = map { split /\s+/ } @lines;

Filter idiom — keep only truthy, transformed values:

my @positives = map { $_ > 0 ? $_ : () } @numbers;

Build a hash from a list — each evaluation returns a two-element list:

my %seen = map { $_ => 1 } @keys;
my %idx  = map { ($keys[$_] => $_) } 0 .. $#keys;

Composed pipeline — sort, filter, transform. map, grep, and sort all take a LIST on the right, so they chain right-to-left:

my @top = map  { "$_->{name}: $_->{score}" }
          sort { $b->{score} <=> $a->{score} }
          grep { $_->{score} >= 50 }
          @records;

Flatten structure — each input contributes a variable number of outputs:

my @leaves = map { ref($_) eq 'ARRAY' ? @$_ : $_ } @mixed;

Pair with index using List::Util::pairs or an explicit index variable — map itself does not expose one:

my @numbered = do {
    my $i = 0;
    map { sprintf "%d. %s", ++$i, $_ } @items;
};

Edge cases#

  • $_ is aliased, not copied. Assigning to $_ writes back to the source. If the source element is read-only (a constant, the return value of a function call flattened into LIST) the assignment raises Modification of a read-only value. Treat $_ as input-only unless you specifically want the side effect.

  • map is not a loop. last, next, redo, and loop labels do not apply to map. They refer to the enclosing real loop and will behave accordingly — usually not what the author intended. Use foreach when you need loop-control flow.

  • Void context is deprecated. map { ... } LIST; with the result discarded emits a Useless use of map in void context warning under use warnings. When you want the side effects, not the list, write a foreach.

  • BLOCK vs EXPR parser ambiguity. { starts both a block and a hash-reference constructor. map { ... } LIST and map { ... }, LIST look identical to the parser at the opening brace; Perl guesses based on what it finds next. A block starting with what looks like a hash key plus => is especially likely to be guessed wrong:

    my %h = map {  "\L$_" => 1  } @a;   # guessed EXPR, wrong
    my %h = map { +"\L$_" => 1  } @a;   # unary + forces BLOCK
    my %h = map {; "\L$_" => 1  } @a;   # leading ; forces BLOCK
    my %h = map { ($_, 1) }       @a;   # parens — unambiguous
    my %h = map { lc($_) => 1 }   @a;   # function call — unambiguous
    

    To return an anonymous hash per element, force the hash-ref constructor with +{:

    my @hashes = map +{ lc($_) => 1 }, @array;
    
  • Order is stable. map evaluates left-to-right and concatenates results left-to-right. The generated list preserves input order, with each input’s contribution appearing contiguously.

  • Empty LIST. map evaluates the block zero times and returns the empty list. The block is not evaluated for its side effects.

  • Nested map. Inner map sees its own $_; the outer $_ is shadowed for the duration of the inner evaluation. Capture the outer value first if both are needed:

    my @pairs = map {
        my $outer = $_;
        map { [$outer, $_] } @inner
    } @outer;
    

Differences from upstream#

Fully compatible with upstream Perl 5.42.

See also#

  • grep — same shape as map, but keeps elements for which the block is true rather than transforming them; chains naturally with map and sort

  • sort — orders a list; commonly composed with map via the Schwartzian transform (mapsortmap)

  • for / foreach — use when you want iteration for side effects, mutation of the source, or loop-control (last/next/redo)

  • x — list repetition operator; orthogonal to map but often used to build the LIST that map consumes

  • List::Util::reduce — fold a list to a single value; use when the result is not a list but an aggregate (sum, max, first match)

  • $_ — the element alias inside the block; read-only when the source element is a literal or function return value