tags:

views:

200

answers:

7

The number of values in a list can only be determined by iterating over 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' ]};

?

A: 

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 :)

dma_k
-1 You should enable warnings and use `qw(a b c)` to understand the folly of you ways.
Sinan Ünür
The difference between lists and arrays is a very important thing to understand.
daotoad
I appreciate your comment, but my answer does not deserve "-1" just because qw{} produce warning. It was used just for demonstration. "-1" means if I did something completely wrong. From other side, if you know the answer, if how to use qw() correctly in this case - tell us.
dma_k
@dma_k Unfortunately, you did do something **completely and utterly wrong** and you do not know enough to know what you did. `'$n = scalar(qw(1 2 3));` assigns `3` to `$n` not because there are three elements in the list but because there is no list: You just demonstrated the comma operator. Try your first example with:`$n = scalar(qw(1 999));`
Sinan Ünür
This is the stupid example we use in _Effective Perl Programming_ to show why people who don't know what they are doing give the wrong answer. In perlfaq4 I specifically use the `qw(1 2 3)` example to show why it gives the wrong answer. That is, the core documentation specfically and explicitly says that this exact answer is wrong. Also, I talk about it in the _Effective Perl_ blog: http://www.effectiveperlprogramming.com/blog/39
brian d foy
+1 For leaving the post here, as a testament to perl's obscure syntax and the perl community's idea of a friendly response :)
Andomar
+7  A: 

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

daotoad
+3  A: 

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.

Sean
+5  A: 

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 = () = ...;

Sinan Ünür
Thanks for benchmarking. Does the size of the list matter? Also, does it matter if you a literal expression defines the list or if it is evaluated at execution time. Are there differences between `'A'..'Z'` and `1 .. 26`? On my perl 5.8 system, goatse is about twice as fast for short lists (10 elements), but for large lists (1000 elements), anon with a literal list beats goatse by about 30%.
daotoad
`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 }, };` Sorry about the crappy formatting.
daotoad
Thanks for your answer, and agree with your conclusion.
eugene y
+1  A: 

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.

Jeff Ober
As has already been said: There is no such thing as a list in scalar context. Lists and arrays are different things in Perl. This post is plain wrong. You are assigning the expression `('a','b','c')` to an **array**. Assignment to an array gives the expression a **list context**. The expression evaluates to a list of 3 values. Those values then assigned to the array. When you evaluate an array in scalar context, it gives the number of members of the array. This is all in perlop. Reread it, paying special attention to how context applies to each operator.
daotoad
+1  A: 

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... :(

Offer Kaye
I think you mean, write-only language :D
Andomar
+1  A: 
Dear Friend, 

 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";
muruga