开发者

How do I find the number of values in a Perl list?

The number of values in a list can only be determined by iterating ove开发者_StackOverflow中文版r its values, or converting it to an array. Assigning it to a scalar won't return the items count:

my $n = ('a', 'b', 'c');  # $n = 'c' 

There's an "empty parentheses" idiom, that can be used to get the number of elements:

my $n = () = ('a', 'b', 'c'); # $n = 3

Is it equivalent internally to

my $n = @{[ 'a', 'b', 'c' ]};

?


The two items you showed are not equivalent. But they have the same final result;

my $n = @{[ 'a', 'b', 'c' ]};

Here you create an anonymous array [ 'a', 'b', 'c' ], then dereference it and take the count of members. The creation of the array provides a list context to the comma operators in the statement.

my $n = () = ('a', 'b', 'c');

Here we use the infamous "goatse operator". The list ('a', 'b', 'c') is assigned to an empty list () = ('a', 'b', 'c'); . The result of the list assignment is assigned to $n. List assignment returns the number of items on the right hand side of the assignment in scalar context (in list context, you get the list of values assigned to).


This is an interesting implementation detail: Does the assignment to an empty list create an (unnecessary) anonymous array?

There are two ways of answering this question: First, The Right Way: Try to figure out how this might be handled in the source. Is there a special case for assignment to an empty list evaluated in scalar context?

Being the lazy and ignorant type, I chose to use Benchmark:

#!/usr/bin/perl

use strict; use warnings;
use Benchmark qw( cmpthese );

cmpthese -5,  {
    goatse => sub { my $n = () = 'A' .. 'Z' },
    anon   => sub { my $n = @{[ 'A' .. 'Z' ]}},
};

I ran the benchmark a bunch of times, and the assignment to empty list had a slight advantage in all cases. If the difference were purely random, the probability of observing 10 timings all in favor of goatse is less than 0.1%, so I am assuming there is some kind of short circuit.

On the other hand, as running the benchmark @daotoad posted in the comments, probably gives a more complete picture:

#!/usr/bin/perl

use strict; use warnings;
use Benchmark qw( cmpthese );

use constant START => 1;
use constant STOP => 1000;

my $start = START;
my $stop = STOP;

cmpthese -5, {
    anon => sub { my $n = @{[ $start .. $stop ]}},
    goatse => sub { my $n = () = $start .. $stop },
    canon => sub { my $n = @{[ START .. STOP ]}},
    cgoatse => sub { my $n = () = START .. STOP },
};

Typical results on my machine (Windows XP Pro SP3, Core 2 Duo, 2 Gb memory, ActiveState perl 5.10.1.1006):

           Rate    anon cgoatse  goatse   canon
anon     5207/s      --    -45%    -49%    -51%
cgoatse  9522/s     83%      --     -7%    -10%
goatse  10201/s     96%      7%      --     -4%
canon   10636/s    104%     12%      4%      --

And, with:

use constant START => 'AAAA';
use constant STOP => 'ZZZZ';

the results are:

          Rate    anon  goatse cgoatse   canon
anon    1.73/s      --    -12%    -16%    -17%
goatse  1.98/s     14%      --     -4%     -5%
cgoatse 2.06/s     19%      4%      --     -1%
canon   2.08/s     20%      5%      1%      --

Conclusion:

If in doubt, use my $n = () = ...;


No. It's equivalent to:

my $n = (() = ('a', 'b', 'c'));

...since the assignment operator is right-associative. The parenthesized list assignment on the right is itself in scalar context, and so its value is the number of items on its right-hand side.


When used in a scalar context, a list evaluates to the number of items within it:

my @list = ('a', 'b', 'c');
my $list_size = @list;

To do an explicit test, such as in an if condition:

my @list = ('a', 'b', 'c');
if (scalar @list == 3) {
  print "@list"; # prints list separated with spaces
}

That will work without the 'scalar' keyword as well. However, that can make your code difficult to scan. Context is a wonderful idea, but it requires more work from the reader. Using scalar explicitly allows the reader to immediately see that you are evaluating @list in a scalar context.


How do I find the number of values in a Perl list?

Assign the list into an @array variable and get the size of the @array using scalar(@array) or using the operation $#array+1. Define sub count {scalar @_} and use calls to count if you have to do this a lot.

my $n = () = ('a', 'b', 'c'); # $n = 3

Sure you can use that... if you want Perl to continue having a bad name as a readonly language... :(


You can use the following code also, to count the no of element in the array or list

use strict;
use warnings;
my @array=(1,2,3,4);
my $i=0;
  foreach(@array)
  {
              $i++;
  }   
 print "The count is:$i\n";


In order to learn the size of array:

  1. Use scalar() to make it explicit (for array references you need to unrefer them via @{...}):

    $ perl -e '$n = scalar(qw(1 2 3)); print $n . "\n"'
    3
    
  2. Use $# (add plus one to get the size):

    $ perl -e '$n = [ 1, 2, 3]; print $#$n . "\n"'
    2
    $ perl -e 'print $#{[ 1, 2, 3]} . "\n"'
    2
    

Perl: there are at least two ways to do it :)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜