3.1.18 Mapping A Function Onto a List
We discuss mapping functions briefly here, for the sake of completion of our discussion on arrays or lists.
Suppose we have a function called square that multiplies a number by itself. If we want to square all the numbers in a list, we can apply the square function to every element of a list. Applying a block of code to every element of a list is called mapping.
Program 3.22
#!/usr/bin/perl
#file map4.pl
use strict 'vars';
use strict 'subs';
$" = ", ";
#a subroutine that multiplies a number by itself
sub square{
my ($n) = @_;
return $n * $n;
}
my @nList = (1, 2, 3, 11);
my @squares = map {square ($_);} @nList;
print "List of squares = @squares\n";
The output printed by this function is given below.
List of squares = 1, 4, 9, 121
The map function, as used here, takes two arguments: a block of statements to execute and a list. Here the block simply contains a call to the square function. This function is called with $_ as the argument. map iterates over every element of a list, and as it iterates over an element of the list, the element is available to it as $_. The result returned by the block of statements for a particular value of $_ is remembered. map collects all the results of such computation and returns them in a list. Thus, map performs an implicit iteration over the elements of a list and also returns an additional result list.
We use the
use strict 'subs';
declaration or pragma to tell Perl that a subroutine name cannot be used before it has been declared.
We do not really have to write a function if the mapped block of statements is simple. We can do the mapping directly. The following program is a rewrite of the program given above.
Program 3.23
#!/usr/bin/perl
use strict 'vars';
$" = ", ";
my @nList = (1, 2, 3, 11);
my @squares = map {$_ * $_;} @nList;
print "List of squares = @squares\n";
If we do not want the results returned by map, but simply want map to have a side effect such as printing something in each iteration, we do not have to assign the result returned by map. The following program prints each squared number on a line by itself.
Program 3.24
#!/usr/bin/perl
use strict 'vars';
my @nList = (1, 2, 3, 11);
map {print $_ * $_, "\n";} @nList;
If we want to have a side-effect such as printing, and also obtain a result list, the mapped block of statements must return a certain value at the end for each element of the list. This can be done by simply evaluating an expression at the end of the block. The value returned by a block of statements is the value returned by the last statement in it.
The following program maps a block of statements onto a list of numbers. The mapped block computes the square and the cube of each number. In addition, it prints the square and the cube for the numbers, one pair per line. The final statement of the block simply evaluates to a list containing two elements: the square and the cube. The last statement of the program prints the returned list.
Program 3.25
#!/usr/bin/perl
use strict 'vars';
$" = ", ";
my @nList = (1, 2, 3, 11);
my @squaresAndCubes = map {my $square = $_ * $_;
my $cube = $square * $_;
print "$square\t$cube\n";
($square, $cube);
}
@nList;
print "List of squares and cubes = @squaresAndCubes\n";
The output of the program is given below.
1 1 4 8 9 27 121 1331 List of squares and cubes = 1, 1, 4, 8, 9, 27, 121, 1331
If the last statement inside the block was removed, the last line of the output printed by the program will be the following.
List of squares and cubes = 1, 1, 1, 1
This is because the print function returns an 1 every time it succeeds in printing something.
If the block of statements that is mapped becomes somewhat large, it makes sense to write it out as a separate function. This function must take one scalar value as argument and return something to construct the resulting list. We can call this function with $_ as the argument inside the mapped block. We had given an example like this in the beginning of this section.
