Book HomeLearning Perl, 3rd EditionSearch this book

17.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 that should be formatted as "money numbers" for output, as with the subroutine &big_money (from Chapter 15, "Strings and Sorting"). But we don't want to modify the original data; 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? So it may not surprise you that 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. And 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 actually becomes part of the resulting list.[363]

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

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 more 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:

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

Of course, we could have done that processing all at once, without even 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 also a simpler syntax for map. If all you need for the selector is a simple expression (rather than a whole block), you can just 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;


Library Navigation Links

Copyright © 2002 O'Reilly & Associates. All rights reserved.