Приглашаем посетить
Бестужев-Марлинский (bestuzhev-marlinskiy.lit-info.ru)

Section 16.3.  Transforming Items from a List with map

Previous
Table of Contents
Next

16.3. Transforming Items from a List with map

Another common task is transforming items from a list. For example, suppose you have a list of numbers to format as money numbers for output, as with the subroutine &big_money (from Chapter 13). We don't want to modify the original data, and we need a modified copy of the list just for output. Here's one way to do that:

    my @data = (4.75, 1.5, 2, 1234, 6.9456, 12345678.9, 29.95);
    my @formatted_data;

    foreach (@data) {
      push @formatted_data, &big_money($_);
    }

That looks similar in form to the example code used at the beginning of the section on grep, doesn't it? The replacement code resembles the first grep example:

    my @data = (4.75, 1.5, 2, 1234, 6.9456, 12345678.9, 29.95);

    my @formatted_data = map { &big_money($_) } @data;

The map operator looks much like grep because it has the same kind of arguments: a block that uses $_ and a list of items to process. It operates in a similar way, evaluating the block once for each item in the list with $_ aliased to a different original list element each time. But the last expression of the block is used differently; instead of giving a Boolean value, the final value becomes part of the resulting list.[*] Any grep or map statement could be rewritten as a foreach loop pushing items onto a temporary array. But the shorter way is typically more efficient and convenient. Since the result of map or grep is a list, it can be passed directly to another function. Here we can print that list of formatted money numbers as an indented list under a heading:

[*] One other important difference is the expression used by map is evaluated in a list context and may return any number of items, not necessarily one each time.

    print "The money numbers are:\n",
      map { sprintf("%25s\n", $_) } @formatted_data;

We could have done that processing all at once without the temporary array @formatted_data:

    my @data = (4.75, 1.5, 2, 1234, 6.9456, 12345678.9, 29.95);
    print "The money numbers are:\n",
      map { sprintf("%25s\n", &big_money($_) ) } @data;

As we saw with grep, there's a simpler syntax for map. If all you need for the selector is a simple expression (rather than a whole block), you can use that expression, followed by a comma, in place of the block:

    print "Some powers of two are:\n",
      map "\t" . ( 2 ** $_ ) . "\n", 0..15;

    Previous
    Table of Contents
    Next