=head1 NAME
-perlfaq4 - Data Manipulation ($Revision: 8539 $)
+perlfaq4 - Data Manipulation ($Revision: 10394 $)
=head1 DESCRIPTION
(contributed by brian d foy)
If you can avoid it, don't, or if you can use a templating system,
-such as C<Text::Template> or C<Template> Toolkit, do that instead.
+such as C<Text::Template> or C<Template> Toolkit, do that instead. You
+might even be able to get the job done with C<sprintf> or C<printf>:
+
+ my $string = sprintf 'Say hello to %s and %s', $foo, $bar;
However, for the one-off simple case where I don't want to pull out a
full templating system, I'll use a string that has two Perl scalar
variables in it. In this example, I want to expand C<$foo> and C<$bar>
-to their variable's values.
+to their variable's values:
my $foo = 'Fred';
my $bar = 'Barney';
C</e> flag. The first C</e> evaluates C<$1> on the replacement side and
turns it into C<$foo>. The second /e starts with C<$foo> and replaces
it with its value. C<$foo>, then, turns into 'Fred', and that's finally
-what's left in the string.
+what's left in the string:
$string =~ s/(\$\w+)/$1/eeg; # 'Say hello to Fred and Barney'
The C</e> will also silently ignore violations of strict, replacing
-undefined variable names with the empty string.
-
-I could also pull the values from a hash instead of evaluating
-variable names. Using a single C</e>, I can check the hash to ensure
-the value exists, and if it doesn't, I can replace the missing value
-with a marker, in this case C<???> to signal that I missed something:
+undefined variable names with the empty string. Since I'm using the
+C</e> flag (twice even!), I have all of the same security problems I
+have with C<eval> in its string form. If there's something odd in
+C<$foo>, perhaps something like C<@{[ system "rm -rf /" ]}>, then
+I could get myself in trouble.
+
+To get around the security problem, I could also pull the values from
+a hash instead of evaluating variable names. Using a single C</e>, I
+can check the hash to ensure the value exists, and if it doesn't, I
+can replace the missing value with a marker, in this case C<???> to
+signal that I missed something:
my $string = 'This has $foo and $bar';
If you are testing only once, the standard module C<List::Util> exports
the function C<first> for this purpose. It works by stopping once it
-finds the element. It's written in C for speed, and its Perl equivalant
+finds the element. It's written in C for speed, and its Perl equivalent
looks like this subroutine:
sub first (&@) {
In general, you usually don't need a linked list in Perl, since with
regular arrays, you can push and pop or shift and unshift at either
end, or you can use splice to add and/or remove arbitrary number of
-elements at arbitrary points. Both pop and shift are both O(1)
+elements at arbitrary points. Both pop and shift are O(1)
operations on Perl's dynamic arrays. In the absence of shifts and
pops, push in general needs to reallocate on the order every log(N)
times, and unshift will need to copy pointers each time.
my $element = $array[ rand @array ];
=head2 How do I permute N elements of a list?
+X<List::Permuter> X<permute> X<Algorithm::Loops> X<Knuth>
+X<The Art of Computer Programming> X<Fischer-Krause>
-Use the C<List::Permutor> module on CPAN. If the list is actually an
+Use the C<List::Permutor> module on CPAN. If the list is actually an
array, try the C<Algorithm::Permute> module (also on CPAN). It's
-written in XS code and is very efficient.
+written in XS code and is very efficient:
use Algorithm::Permute;
+
my @array = 'a'..'d';
my $p_iterator = Algorithm::Permute->new ( \@array );
+
while (my @perm = $p_iterator->next) {
print "next permutation: (@perm)\n";
}
For even faster execution, you could do:
use Algorithm::Permute;
+
my @array = 'a'..'d';
+
Algorithm::Permute::permute {
print "next permutation: (@array)\n";
} @array;
-Here's a little program that generates all permutations of
-all the words on each line of input. The algorithm embodied
-in the C<permute()> function is discussed in Volume 4 (still
-unpublished) of Knuth's I<The Art of Computer Programming>
-and will work on any list:
+Here's a little program that generates all permutations of all the
+words on each line of input. The algorithm embodied in the
+C<permute()> function is discussed in Volume 4 (still unpublished) of
+Knuth's I<The Art of Computer Programming> and will work on any list:
#!/usr/bin/perl -n
- # Fischer-Kause ordered permutation generator
+ # Fischer-Krause ordered permutation generator
sub permute (&@) {
my $code = shift;
}
}
- permute {print"@_\n"} split;
+ permute { print "@_\n" } split;
+
+The C<Algorithm::Loops> module also provides the C<NextPermute> and
+C<NextPermuteNum> functions which efficiently find all unique permutations
+of an array, even if it contains duplicate values, modifying it in-place:
+if its elements are in reverse-sorted order then the array is reversed,
+making it sorted, and it returns false; otherwise the next
+permutation is returned.
+
+C<NextPermute> uses string order and C<NextPermuteNum> numeric order, so
+you can enumerate all the permutations of C<0..9> like this:
+
+ use Algorithm::Loops qw(NextPermuteNum);
+
+ my @list= 0..9;
+ do { print "@list\n" } while NextPermuteNum @list;
=head2 How do I sort an array by (anything)?
$hash{'d'} is false
defined $hash{'d'} is true
defined $hash{'a'} is true
- exists $hash{'a'} is true (Perl5 only)
+ exists $hash{'a'} is true (Perl 5 only)
grep ($_ eq 'a', keys %hash) is true
If you now say
$hash{'d'} is false
defined $hash{'d'} is true
defined $hash{'a'} is FALSE
- exists $hash{'a'} is true (Perl5 only)
+ exists $hash{'a'} is true (Perl 5 only)
grep ($_ eq 'a', keys %hash) is true
Notice the last two: you have an undef value, but a defined key!
$hash{'d'} is false
defined $hash{'d'} is true
defined $hash{'a'} is false
- exists $hash{'a'} is FALSE (Perl5 only)
+ exists $hash{'a'} is FALSE (Perl 5 only)
grep ($_ eq 'a', keys %hash) is FALSE
See, the whole entry is gone!
=head2 How do I reset an each() operation part-way through?
-Using C<keys %hash> in scalar context returns the number of keys in
-the hash I<and> resets the iterator associated with the hash. You may
-need to do this if you use C<last> to exit a loop early so that when
-you re-enter it, the hash iterator has been reset.
+(contributed by brian d foy)
+
+You can use the C<keys> or C<values> functions to reset C<each>. To
+simply reset the iterator used by C<each> without doing anything else,
+use one of them in void context:
+
+ keys %hash; # resets iterator, nothing else.
+ values %hash; # resets iterator, nothing else.
+
+See the documentation for C<each> in L<perlfunc>.
=head2 How can I get the unique keys from two hashes?
=head1 REVISION
-Revision: $Revision: 8539 $
+Revision: $Revision: 10394 $
-Date: $Date: 2007-01-11 00:07:14 +0100 (jeu, 11 jan 2007) $
+Date: $Date: 2007-12-09 18:47:15 +0100 (Sun, 09 Dec 2007) $
See L<perlfaq> for source control details and availability.