⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 perlfaq4.pod

📁 ARM上的如果你对底层感兴趣
💻 POD
📖 第 1 页 / 共 3 页
字号:
            print "@perms\n";
	} else {
            my(@newitems,@newperms,$i);
            foreach $i (0 .. $#items) {
                @newitems = @items;
                @newperms = @perms;
                unshift(@newperms, splice(@newitems, $i, 1));
                permute([@newitems], [@newperms]);
	    }
	}
    }

=head2 How do I sort an array by (anything)?

Supply a comparison function to sort() (described in L<perlfunc/sort>):

    @list = sort { $a <=> $b } @list;

The default sort function is cmp, string comparison, which would
sort C<(1, 2, 10)> into C<(1, 10, 2)>.  C<E<lt>=E<gt>>, used above, is
the numerical comparison operator.

If you have a complicated function needed to pull out the part you
want to sort on, then don't do it inside the sort function.  Pull it
out first, because the sort BLOCK can be called many times for the
same element.  Here's an example of how to pull out the first word
after the first number on each item, and then sort those words
case-insensitively.

    @idx = ();
    for (@data) {
	($item) = /\d+\s*(\S+)/;
	push @idx, uc($item);
    }
    @sorted = @data[ sort { $idx[$a] cmp $idx[$b] } 0 .. $#idx ];

Which could also be written this way, using a trick
that's come to be known as the Schwartzian Transform:

    @sorted = map  { $_->[0] }
	      sort { $a->[1] cmp $b->[1] }
	      map  { [ $_, uc((/\d+\s*(\S+)/ )[0] ] } @data;

If you need to sort on several fields, the following paradigm is useful.

    @sorted = sort { field1($a) <=> field1($b) ||
                     field2($a) cmp field2($b) ||
                     field3($a) cmp field3($b)
                   }     @data;

This can be conveniently combined with precalculation of keys as given
above.

See http://www.perl.com/CPAN/doc/FMTEYEWTK/sort.html for more about
this approach.

See also the question below on sorting hashes.

=head2 How do I manipulate arrays of bits?

Use pack() and unpack(), or else vec() and the bitwise operations.

For example, this sets $vec to have bit N set if $ints[N] was set:

    $vec = '';
    foreach(@ints) { vec($vec,$_,1) = 1 }

And here's how, given a vector in $vec, you can
get those bits into your @ints array:

    sub bitvec_to_list {
	my $vec = shift;
	my @ints;
	# Find null-byte density then select best algorithm
	if ($vec =~ tr/\0// / length $vec > 0.95) {
	    use integer;
	    my $i;
	    # This method is faster with mostly null-bytes
	    while($vec =~ /[^\0]/g ) {
		$i = -9 + 8 * pos $vec;
		push @ints, $i if vec($vec, ++$i, 1);
		push @ints, $i if vec($vec, ++$i, 1);
		push @ints, $i if vec($vec, ++$i, 1);
		push @ints, $i if vec($vec, ++$i, 1);
		push @ints, $i if vec($vec, ++$i, 1);
		push @ints, $i if vec($vec, ++$i, 1);
		push @ints, $i if vec($vec, ++$i, 1);
		push @ints, $i if vec($vec, ++$i, 1);
	    }
	} else {
	    # This method is a fast general algorithm
	    use integer;
	    my $bits = unpack "b*", $vec;
	    push @ints, 0 if $bits =~ s/^(\d)// && $1;
	    push @ints, pos $bits while($bits =~ /1/g);
	}
	return \@ints;
    }

This method gets faster the more sparse the bit vector is.
(Courtesy of Tim Bunce and Winfried Koenig.)

=head2 Why does defined() return true on empty arrays and hashes?

See L<perlfunc/defined> in the 5.004 release or later of Perl.

=head1 Data: Hashes (Associative Arrays)

=head2 How do I process an entire hash?

Use the each() function (see L<perlfunc/each>) if you don't care
whether it's sorted:

    while ( ($key, $value) = each %hash) {
	print "$key = $value\n";
    }

If you want it sorted, you'll have to use foreach() on the result of
sorting the keys as shown in an earlier question.

=head2 What happens if I add or remove keys from a hash while iterating over it?

Don't do that.

=head2 How do I look up a hash element by value?

Create a reverse hash:

    %by_value = reverse %by_key;
    $key = $by_value{$value};

That's not particularly efficient.  It would be more space-efficient
to use:

    while (($key, $value) = each %by_key) {
	$by_value{$value} = $key;
    }

If your hash could have repeated values, the methods above will only
find one of the associated keys.   This may or may not worry you.

=head2 How can I know how many entries are in a hash?

If you mean how many keys, then all you have to do is
take the scalar sense of the keys() function:

    $num_keys = scalar keys %hash;

In void context it just resets the iterator, which is faster
for tied hashes.

=head2 How do I sort a hash (optionally by value instead of key)?

Internally, hashes are stored in a way that prevents you from imposing
an order on key-value pairs.  Instead, you have to sort a list of the
keys or values:

    @keys = sort keys %hash;	# sorted by key
    @keys = sort {
		    $hash{$a} cmp $hash{$b}
	    } keys %hash; 	# and by value

Here we'll do a reverse numeric sort by value, and if two keys are
identical, sort by length of key, and if that fails, by straight ASCII
comparison of the keys (well, possibly modified by your locale -- see
L<perllocale>).

    @keys = sort {
		$hash{$b} <=> $hash{$a}
			  ||
		length($b) <=> length($a)
			  ||
		      $a cmp $b
    } keys %hash;

=head2 How can I always keep my hash sorted?

You can look into using the DB_File module and tie() using the
$DB_BTREE hash bindings as documented in L<DB_File/"In Memory Databases">.
The Tie::IxHash module from CPAN might also be instructive.

=head2 What's the difference between "delete" and "undef" with hashes?

Hashes are pairs of scalars: the first is the key, the second is the
value.  The key will be coerced to a string, although the value can be
any kind of scalar: string, number, or reference.  If a key C<$key> is
present in the array, C<exists($key)> will return true.  The value for
a given key can be C<undef>, in which case C<$array{$key}> will be
C<undef> while C<$exists{$key}> will return true.  This corresponds to
(C<$key>, C<undef>) being in the hash.

Pictures help...  here's the C<%ary> table:

	  keys  values
	+------+------+
	|  a   |  3   |
	|  x   |  7   |
	|  d   |  0   |
	|  e   |  2   |
	+------+------+

And these conditions hold

	$ary{'a'}                       is true
	$ary{'d'}                       is false
	defined $ary{'d'}               is true
	defined $ary{'a'}               is true
	exists $ary{'a'}                is true (perl5 only)
	grep ($_ eq 'a', keys %ary)     is true

If you now say

	undef $ary{'a'}

your table now reads:


	  keys  values
	+------+------+
	|  a   | undef|
	|  x   |  7   |
	|  d   |  0   |
	|  e   |  2   |
	+------+------+

and these conditions now hold; changes in caps:

	$ary{'a'}                       is FALSE
	$ary{'d'}                       is false
	defined $ary{'d'}               is true
	defined $ary{'a'}               is FALSE
	exists $ary{'a'}                is true (perl5 only)
	grep ($_ eq 'a', keys %ary)     is true

Notice the last two: you have an undef value, but a defined key!

Now, consider this:

	delete $ary{'a'}

your table now reads:

	  keys  values
	+------+------+
	|  x   |  7   |
	|  d   |  0   |
	|  e   |  2   |
	+------+------+

and these conditions now hold; changes in caps:

	$ary{'a'}                       is false
	$ary{'d'}                       is false
	defined $ary{'d'}               is true
	defined $ary{'a'}               is false
	exists $ary{'a'}                is FALSE (perl5 only)
	grep ($_ eq 'a', keys %ary)     is FALSE

See, the whole entry is gone!

=head2 Why don't my tied hashes make the defined/exists distinction?

They may or may not implement the EXISTS() and DEFINED() methods
differently.  For example, there isn't the concept of undef with hashes
that are tied to DBM* files. This means the true/false tables above
will give different results when used on such a hash.  It also means
that exists and defined do the same thing with a DBM* file, and what
they end up doing is not what they do with ordinary hashes.

=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.

=head2 How can I get the unique keys from two hashes?

First you extract the keys from the hashes into arrays, and then solve
the uniquifying the array problem described above.  For example:

    %seen = ();
    for $element (keys(%foo), keys(%bar)) {
	$seen{$element}++;
    }
    @uniq = keys %seen;

Or more succinctly:

    @uniq = keys %{{%foo,%bar}};

Or if you really want to save space:

    %seen = ();
    while (defined ($key = each %foo)) {
        $seen{$key}++;
    }
    while (defined ($key = each %bar)) {
        $seen{$key}++;
    }
    @uniq = keys %seen;

=head2 How can I store a multidimensional array in a DBM file?

Either stringify the structure yourself (no fun), or else
get the MLDBM (which uses Data::Dumper) module from CPAN and layer
it on top of either DB_File or GDBM_File.

=head2 How can I make my hash remember the order I put elements into it?

Use the Tie::IxHash from CPAN.

    use Tie::IxHash;
    tie(%myhash, Tie::IxHash);
    for ($i=0; $i<20; $i++) {
        $myhash{$i} = 2*$i;
    }
    @keys = keys %myhash;
    # @keys = (0,1,2,3,...)

=head2 Why does passing a subroutine an undefined element in a hash create it?

If you say something like:

    somefunc($hash{"nonesuch key here"});

Then that element "autovivifies"; that is, it springs into existence
whether you store something there or not.  That's because functions
get scalars passed in by reference.  If somefunc() modifies C<$_[0]>,
it has to be ready to write it back into the caller's version.

This has been fixed as of perl5.004.

Normally, merely accessing a key's value for a nonexistent key does
I<not> cause that key to be forever there.  This is different than
awk's behavior.

=head2 How can I make the Perl equivalent of a C structure/C++ class/hash or array of hashes or arrays?

Use references (documented in L<perlref>).  Examples of complex data
structures are given in L<perldsc> and L<perllol>.  Examples of
structures and object-oriented classes are in L<perltoot>.

=head2 How can I use a reference as a hash key?

You can't do this directly, but you could use the standard Tie::Refhash
module distributed with perl.

=head1 Data: Misc

=head2 How do I handle binary data correctly?

Perl is binary clean, so this shouldn't be a problem.  For example,
this works fine (assuming the files are found):

    if (`cat /vmunix` =~ /gzip/) {
	print "Your kernel is GNU-zip enabled!\n";
    }

On some systems, however, you have to play tedious games with "text"
versus "binary" files.  See L<perlfunc/"binmode">.

If you're concerned about 8-bit ASCII data, then see L<perllocale>.

If you want to deal with multibyte characters, however, there are
some gotchas.  See the section on Regular Expressions.

=head2 How do I determine whether a scalar is a number/whole/integer/float?

Assuming that you don't care about IEEE notations like "NaN" or
"Infinity", you probably just want to use a regular expression.

   warn "has nondigits"        if     /\D/;
    warn "not a natural number" unless /^\d+$/;             # rejects -3
    warn "not an integer"       unless /^-?\d+$/;           # rejects +3
   warn "not an integer"       unless /^[+-]?\d+$/;
   warn "not a decimal number" unless /^-?\d+\.?\d*$/;  # rejects .2
   warn "not a decimal number" unless /^-?(?:\d+(?:\.\d*)?|\.\d+)$/;
   warn "not a C float"
       unless /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/;

If you're on a POSIX system, Perl's supports the C<POSIX::strtod>
function.  Its semantics are somewhat cumbersome, so here's a C<getnum>
wrapper function for more convenient access.  This function takes
a string and returns the number it found, or C<undef> for input that
isn't a C float.  The C<is_numeric> function is a front end to C<getnum>
if you just want to say, ``Is this a float?''

    sub getnum {
        use POSIX qw(strtod);
        my $str = shift;
        $str =~ s/^\s+//;
        $str =~ s/\s+$//;
        $! = 0;
        my($num, $unparsed) = strtod($str);
        if (($str eq '') || ($unparsed != 0) || $!) {
            return undef;
        } else {
            return $num;
        } 
    } 

    sub is_numeric { defined &getnum } 

Or you could check out
http://www.perl.com/CPAN/modules/by-module/String/String-Scanf-1.1.tar.gz
instead.  The POSIX module (part of the standard Perl distribution)
provides the C<strtol> and C<strtod> for converting strings to double
and longs, respectively.

=head2 How do I keep persistent data across program calls?

For some specific applications, you can use one of the DBM modules.
See L<AnyDBM_File>.  More generically, you should consult the
FreezeThaw, Storable, or Class::Eroot modules from CPAN.

=head2 How do I print out or copy a recursive data structure?

The Data::Dumper module on CPAN is nice for printing out
data structures, and FreezeThaw for copying them.  For example:

    use FreezeThaw qw(freeze thaw);
    $new = thaw freeze $old;

Where $old can be (a reference to) any kind of data structure you'd like.
It will be deeply copied.

=head2 How do I define methods for every class/object?

Use the UNIVERSAL class (see L<UNIVERSAL>).

=head2 How do I verify a credit card checksum?

Get the Business::CreditCard module from CPAN.

=head1 AUTHOR AND COPYRIGHT

Copyright (c) 1997, 1998 Tom Christiansen and Nathan Torkington.
All rights reserved.

When included as part of the Standard Version of Perl, or as part of
its complete documentation whether printed or otherwise, this work
may be distributed only under the terms of Perl's Artistic License.
Any distribution of this file or derivatives thereof I<outside>
of that package require that special arrangements be made with
copyright holder.

Irrespective of its distribution, all code examples in this file
are hereby placed into the public domain.  You are permitted and
encouraged to use this code in your own programs for fun
or for profit as you see fit.  A simple comment in the code giving
credit would be courteous but is not required.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -