Recipe 4.1 Specifying a List in Your Program4.1.1 ProblemYou want to include a list in your program. This is how you initialize arrays. 4.1.2 SolutionYou can write out a comma-separated list of elements:
@a = ("quick", "brown", "fox");
If you have a lot of single-word elements, use the qw( ) operator: @a = qw(Meddle not in the affairs of wizards.); If you have a lot of multiword elements, use a here document and extract lines:
@lines = (<< "END_OF_HERE_DOC" =~ /^\s*(.+)/gm);
I sit beside the fire and think
of all that I have seen,
of meadow-flowers and butterflies
and summers that have been;
END_OF_HERE_DOC
4.1.3 Discussion
The first technique is the one most commonly used, often because only small arrays are normally initialized as program literals. Initializing a large array would fill your program with values and make it hard to read, so such arrays either tend to be
@bigarray = ( );
open(FH, "<", "myinfo") or die "Couldn't open myinfo: $!";
while (<FH>) {
chomp;
push(@bigarray, $_);
}
close(FH);
The second technique uses
qw( )
, one of several pseudo-functions in Perl used for quoting without having to resort to actual quotation marks. This one
@banner = ('Costs', 'only', '.95');
@banner = qw(Costs only .95);
@banner = split(' ', 'Costs only .95');
You can use qw( ) only when each whitespace-separated argument is to be a distinct element in the return list. Be careful not to give Columbus four ships instead of three:
@ships = qw(Niña Pinta Santa María); # WRONG
@ships = ('Niña', 'Pinta', 'Santa María'); # right
The third solution takes a here document, which is a single, multiline string, and applies a global pattern match to that string. The pattern /^\s*(.+)/ says to skip any whitespace at the start of the line, then capture everything through the end of each line. The /g modifier means to apply that match globally, and the /m modifier says to permit ^ to match not just at the beginning of the string, but also immediately after a newline, which, in a multiline string, is just what you need. Applying that technique to the ships example yields:
@ships = ( << "END_OF_FLOTILLA" =~ /^\s*(.+)/gm);
Niña
Pinta
Santa María
END_OF_FLOTILLA
4.1.4 See AlsoThe "List Value Constructors" section of perldata (1); the "List Values and Arrays" section of Chapter 2 of Programming Perl ; the "Quote and Quote-Like Operators" section of perlop (1); the s/// operator in perlop (1) and Chapter 5 of Programming Perl |
Recipe 4.2 Printing a List with Commas4.2.1 ProblemYou'd like to print out a list containing an unknown number of elements, placing an "and" before the last element and commas between each element if there are more than two. 4.2.2 SolutionUse this function, which returns the formatted string:
sub commify_series {
(@_ = = 0) ? '' :
(@_ = = 1) ? $_[0] :
(@_ = = 2) ? join(" and ", @_) :
join(", ", @_[0 .. ($#_-1)], "and $_[-1]");
}
4.2.3 DiscussionIt often looks odd to print out arrays:
@array = ("red", "yellow", "green");
print "I have ", @array, " marbles.\n";
print "I have @array marbles.\n";
I have redyellowgreen marbles
.
I have red yellow green marbles
.
What you really want it to say is, " I have red , yellow , and green marbles ". The function given in the solution generates strings in that format. The word " and " is placed between the last two list elements. If there are more than two elements in the list, a comma is placed between every element. Example 4-1 gives a complete demonstration of the function, with one addition: if any element in the list already contains a comma, a semicolon is used for the separator character instead. Example 4-1. commify_series
#!/usr/bin/perl -w
# commify_series - show proper comma insertion in list output
# @lists is an array of (references to anonymous) arrays
@lists = (
[ 'just one thing' ],
[ qw(Mutt Jeff) ],
[ qw(Peter Paul Mary) ],
[ 'To our parents', 'Mother Theresa', 'God' ],
[ 'pastrami', 'ham and cheese', 'peanut butter and jelly', 'tuna' ],
[ 'recycle tired, old phrases', 'ponder big, happy thoughts' ],
[ 'recycle tired, old phrases',
'ponder big, happy thoughts',
'sleep and dream peacefully' ],
);
foreach $aref (@lists) {
print "The list is: " . commify_series(@$aref) . ".\n";
}
# demo for single list
@list = qw(one two three);
print "The last list is: " . commify_series(@list) . ".\n";
sub commify_series {
my $sepchar = grep(/,/ => @_) ? ";" : ",";
(@_ = = 0) ? '' :
(@_ = = 1) ? $_[0] :
(@_ = = 2) ? join(" and ", @_) :
join("$sepchar ", @_[0 .. ($#_-1)], "and $_[-1]");
}
Here's the output from the program: The list is: just one thing . The list is: Mutt and Jeff . The list is: Peter, Paul, and Mary . The list is: To our parents, Mother Theresa, and God . The list is: pastrami, ham and cheese, peanut butter and jelly, and tuna . The list is: recycle tired, old phrases and ponder big, happy thoughts . The list is: recycle tired, old phrases; ponder big, happy thoughts; and sleep and dream peacefully . The last list is: one, two, and three .
As you see, we don't follow the ill-advised practice of omitting the final comma from a series under any circumstances. To do so introduces unfortunate
4.2.4 See AlsoFowler's Modern English Usage ; we explain the nested list syntax in Recipe 11.1; the grep function in perlfunc (1) and Chapter 29 of Programming Perl ; the conditional operator ("?:") is discussed in perlop (1) and in the "Conditional Operator" section of Chapter 3 of Programming Perl |