Find size of an array in Perl
Asked Answered
G

12

281

I seem to have come across several different ways to find the size of an array. What is the difference between these three methods?

my @arr = (2);
print scalar @arr; # First way to print array size

print $#arr; # Second way to print array size

my $arrSize = @arr;
print $arrSize; # Third way to print array size
Giaour answered 13/9, 2011 at 18:40 Comment(5)
other ways: print 0+@arr, print "".@arr, print ~~@arrWaugh
@mob, hum, one might want to avoid "".@arr as "@arr" does something quite different.Haines
The "second way" is NOT a way to print the array size...Riel
in scalar context ;@arr returns table size. $x=@arr is scalar context. $#arr returns last index of array. indexing starting at 0, then is true equation $#arr+1 == @arr . If you write some element out of order, for example $arr[100]='any', then table is automatically increased to max index 100, and (including index 0) to 101 elements.Equiangular
Candidates: What does $#array mean in Perl? (2008-10-27)Tessin
F
265

The first and third ways are the same: they evaluate an array in scalar context. I would consider this to be the standard way to get an array's size.

The second way actually returns the last index of the array, which is not (usually) the same as the array size.

Fleuron answered 13/9, 2011 at 18:44 Comment(8)
What's the difference between the last index and the array size? Is the index not sequential from 0 to the array size?Giaour
The size of (1,2,3) is 3, and the indexes are (by default) 0, 1 and 2. So, $#arr will be 2 in this case, not 3.Dympha
The predefined variable $[ specifies "The index of the first element in an array, and of the first character in a substring" (perldoc perlvar). It's set to 0 by default, and setting it to anything other than 0 is highly discouraged.Savick
@Keith Thompson, $[ is discouraged (and has been for a decade). $[ is deprecated. Using $[ issues a deprecation warning even when one doesn't turn on warnings. Assigning anything but zero to $[ will be an error in 5.16. Can we stop mentioning $[ already?Haines
@ikegami: Sure, we can stop mentioning $[ as soon as everyone in the world stops using versions of Perl older than 5.16. 8-)}Savick
@Keith Thompson, Older than 5.14, actually. But like I said, it's been discouraged and deprecated for far longer than that, and someone using $[ would know of its effects.Haines
@ikegami: Yes, but someone trying to understand the difference between scalar @arr and $#arr should still understand the possible effects of $[, rare though they are.Savick
@Keith Tompson, I beg to differ. Someone who doesn't use $[ doesn't need to know about its effects. And as I already said, the person using $[ --if the person even exists-- already knows its effects. There's no point in going through all this for the benefit of the non-existent person that uses $[ without knowing what it is.Haines
H
49

First, the second ($#array) is not equivalent to the other two. $#array returns the last index of the array, which is one less than the size of the array.

The other two (scalar @arr and $arrSize = @arr) are virtually the same. You are simply using two different means to create scalar context. It comes down to a question of readability.

I personally prefer the following:

say 0+@array;          # Represent @array as a number

I find it clearer than

say scalar(@array);    # Represent @array as a scalar

and

my $size = @array;
say $size;

The latter looks quite clear alone like this, but I find that the extra line takes away from clarity when part of other code. It's useful for teaching what @array does in scalar context, and maybe if you want to use $size more than once.

Haines answered 13/9, 2011 at 19:0 Comment(13)
Personally I prefer the version that uses the "scalar" keyword, because it's quite explicit that it's forcing a scalar context. my $size=@array looks like it might be a mistake where the wrong sigil was used.Dympha
That's a really bad idea. People who use scalar for no reason learn the wrong lesson. They start getting into their heads that operators return lists that can be coerced into scalars. Seen it dozens of times.Haines
Why is this "no reason"? You are using scalar because you are coercing the list to a scalar context. That is the right reason to use it. Your example does exactly the same thing, but relies on what Perl does when you evaluate a list variable in an implicitly scalar context. Thus, your example requires the reader to know about Perl's implicit behavior in that context. You're just adding one more layer of implicit behavior to the expression, and Perl already has too much implicit behavior that you have to reason through to decipher a program.Dympha
@Nate C-K, Re "Why is this "no reason"? You are using scalar because you are coercing the list to a scalar context", You've proving my point about learning the wrong lesson. This is completely false. No list is ever coerced by scalar. (If it did, scalar(@array) and scalar(@array[0..$#array]) would return the same thing.) scalar(@array) tells @array to return a scalar, which you already told it to do with my $size=.Haines
The original example wasn't my $size = scalar(@array);, it was say scalar(@array);. I see what you mean about the assignment, that in that context it is redundant, although as I pointed out before it clarifies your intent (since mixing up sigils is an extremely common mistake in Perl).Dympha
@Nate C-K, Re "The original example wasn't my $size = scalar(@array);", So? I never said there was no reason for scalar in the original. It was in reply to you saying my $size=@array; shouldn't be used.Haines
@Nate C-K, Re "it clarifies your intent", How so? Does anything think you can assign something other than a scalar to a scalar? No, it superfluous and harmful.Haines
As I said (twice), because it's possible to mix up the sigils. Programmers write my $x = @y when they meant my @x = @y or my $x = $y. This happens all the time in Perl, whether it's due to confusion or just a simple typo.Dympha
@Nate C-K, Re "it's possible to mix up the sigils", 1) I know you said that, but it doesn't answer my question. I asked how does scalar($x) clarify intent? 2) Re "Programmers write my $x = @y when they meant my @x = @y or my $x = $y", No they don't. The program wouldn't work.Haines
Yes... that's why it's a bug.Dympha
@Nate C-K, It won't even compile, so the only reader is the programmer who just wrote the code. You're saying he needs to tell himself what he means as he's writing the code? nah. No reason to do that. How about you have the programmer remember to use a scalar rather than remember to use scalar.Haines
Believe it or not, developers have to debug code written by other developers. And developers have to debug code that they wrote three years ago.Dympha
@Nate C-K, I'm not too worried about the programmer's ability to debug a program noone ever ran.Haines
D
32

This gets the size by forcing the array into a scalar context, in which it is evaluated as its size:

print scalar @arr;

This is another way of forcing the array into a scalar context, since it's being assigned to a scalar variable:

my $arrSize = @arr;

This gets the index of the last element in the array, so it's actually the size minus 1 (assuming indexes start at 0, which is adjustable in Perl although doing so is usually a bad idea):

print $#arr;

This last one isn't really good to use for getting the array size. It would be useful if you just want to get the last element of the array:

my $lastElement = $arr[$#arr];

Also, as you can see here on Stack Overflow, this construct isn't handled correctly by most syntax highlighters...

Dympha answered 13/9, 2011 at 18:44 Comment(2)
A sidenote: just use $arr[-1] to get the last element. And $arr[-2] to get the penultimate one, and so on.Slow
@tuomassalo: I agree that your suggestion is a better approach. In retrospect, $#arr isn't a very useful feature, and it's no accident that other languages don't have it.Dympha
B
8

To use the second way, add 1:

print $#arr + 1; # Second way to print array size
Bilyeu answered 14/9, 2013 at 3:29 Comment(1)
for [0..$#array] { print $array[$_ ] } works really well though if the purpose of getting the number of elements is to iterate through array. The advantage being that you get the element as well as a counter that are aligned.Iodous
C
6

All three give the same result if we modify the second one a bit:

my @arr = (2, 4, 8, 10);

print "First result:\n";
print scalar @arr; 

print "\n\nSecond result:\n";
print $#arr + 1; # Shift numeration with +1 as it shows last index that starts with 0.

print "\n\nThird result:\n";
my $arrSize = @arr;
print $arrSize;
Chargeable answered 23/10, 2013 at 4:32 Comment(1)
Is this anything different from what has already been mentioned in this answer and this one?Pegg
W
5

Example:

my @a = (undef, undef);
my $size = @a;

warn "Size: " . $#a;   # Size: 1. It's not the size
warn "Size: " . $size; # Size: 2
Whatnot answered 12/6, 2013 at 7:48 Comment(0)
C
3

The “Perl variable types” section of the perlintro documentation contains

The special variable $#array tells you the index of the last element of an array:

print $mixed[$#mixed];       # last element, prints 1.23

You might be tempted to use $#array + 1 to tell you how many items there are in an array. Don’t bother. As it happens, using @array where Perl expects to find a scalar value (“in scalar context”) will give you the number of elements in the array:

if (@animals < 5) { ... }

The perldata documentation also covers this in the “Scalar values” section.

If you evaluate an array in scalar context, it returns the length of the array. (Note that this is not true of lists, which return the last value, like the C comma operator, nor of built-in functions, which return whatever they feel like returning.) The following is always true:

scalar(@whatever) == $#whatever + 1;

Some programmers choose to use an explicit conversion so as to leave nothing to doubt:

$element_count = scalar(@whatever);

Earlier in the same section documents how to obtain the index of the last element of an array.

The length of an array is a scalar value. You may find the length of array @days by evaluating $#days, as in csh. However, this isn’t the length of the array; it’s the subscript of the last element, which is a different value since there is ordinarily a 0th element.

Counteroffensive answered 3/8, 2015 at 15:48 Comment(0)
N
3

From perldoc perldata, which should be safe to quote:

The following is always true:

scalar(@whatever) == $#whatever + 1;

Just so long as you don't $#whatever++ and mysteriously increase the size or your array.

The array indices start with 0.

and

You can truncate an array down to nothing by assigning the null list () to it. The following are equivalent:

    @whatever = ();
    $#whatever = -1;

Which brings me to what I was looking for which is how to detect the array is empty. I found it if $#empty == -1;

Nalepka answered 6/5, 2017 at 21:40 Comment(0)
L
3

There are various ways to print size of an array. Here are the meanings of all:

Let’s say our array is my @arr = (3,4);

Method 1: scalar

This is the right way to get the size of arrays.

print scalar @arr;  # Prints size, here 2

Method 2: Index number

$#arr gives the last index of an array. So if array is of size 10 then its last index would be 9.

print $#arr;     # Prints 1, as last index is 1
print $#arr + 1; # Adds 1 to the last index to get the array size

We are adding 1 here, considering the array as 0-indexed. But, if it's not zero-based then, this logic will fail.

perl -le 'local $[ = 4; my @arr = (3, 4); print $#arr + 1;'   # prints 6

The above example prints 6, because we have set its initial index to 4. Now the index would be 5 and 6, with elements 3 and 4 respectively.

Method 3:

When an array is used in a scalar context, then it returns the size of the array

my $size = @arr;
print $size;   # Prints size, here 2

Actually, method 3 and method 1 are same.

Lyell answered 9/5, 2017 at 15:12 Comment(0)
F
1

Use int(@array) as it threats the argument as scalar.

Forefinger answered 13/3, 2018 at 20:42 Comment(0)
P
0

To find the size of an array use the scalar keyword:

print scalar @array;

To find out the last index of an array there is $# (Perl default variable). It gives the last index of an array. As an array starts from 0, we get the size of array by adding one to $#:

print "$#array+1";

Example:

my @a = qw(1 3 5);
print scalar @a, "\n";
print $#a+1, "\n";

Output:

3

3
Partan answered 30/3, 2017 at 9:40 Comment(1)
What do you mean by "Perl default variable"?Tessin
C
0

As numerous answers pointed out, the first and third way are the correct methods to get the array size, and the second way is not.

Here I expand on these answers with some usage examples.

@array_name evaluates to the length of the array = the size of the array = the number of elements in the array, when used in a scalar context.

Below are some examples of a scalar context, such as @array_name by itself inside if or unless, of in arithmetic comparisons such as == or !=.

All of these examples will work if you change @array_name to scalar(@array_name). This would make the code more explicit, but also longer and slightly less readable. Therefore, more idiomatic usage omitting scalar() is preferred here.

my @a = (undef, q{}, 0, 1);

# All of these test whether 'array' has four elements:
print q{array has four elements} if @a == 4;
print q{array has four elements} unless @a != 4;
@a == 4 and print q{array has four elements};
!(@a != 4) and print q{array has four elements};

# All of the above print:
# array has four elements

# All of these test whether array is not empty:
print q{array is not empty} if @a;
print q{array is not empty} unless !@a;
@a and print q{array is not empty};
!(!@a) and print q{array is not empty};

# All of the above print:
# array is not empty
Chartulary answered 25/8, 2020 at 16:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.