Survey of $#array Usage


        $element_count = $#Array;

Note that the variable name erroneously states that the variable contains a count of the elements.


Same as 1352.


Although not explicitly obfuscated, the code was very difficult to understand:

        @seen{map {
        	my $la = $_;
        	map { $la->[$_ & ~1] } 2 .. $#$la;
        } $parser->links} = ();

$parser->links here returns a data structure of the form

        ([P, a,1,b,2,c,3], [Q, d,4,e,5], [R, f,6,g,7,a,8], [S, b,9,e,19,g,11]);

(Apparently it is the return from HTML::LinkExtor.) The goal here is to create a hash whose keys are 1, 2, 3, 4, etc. The values are unimportant.

The author says:

I wouldn't suggest using it, but you might have been considering it.


The code was

        my $sortkeys = join " || ",
          map "\$a->{\$sortkeys[$_]} cmp \$b->{\$sortkeys[$_]}", 0..$#sortkeys;

Although it's tempting to suggest that it could be replaced with a simpler, $#array-less version:

        my $sortkeys = join " || ",
          map "\$a->{$_} cmp \$b->{$_}", @sortkeys;

that would not be correct in this case. The author wanted to consider the situation where @sortkeys might contain elements with spaces or other punctuation characters, and the complicated version is required for this.


The poster is constructing a three-dimensional array and wants to replace an index loop with en element loop:

        2) I use a[i][j][k] for getting/setting values, its
           3 loops and is cumbersume.

        3) I'd like to know how I can get/set values without using indexes.

          i.e for a simple array:
        instead of
           for ($i=0; $i <=$#ARR; $i++)

        I'd like to use
           for $val (@ARR)

        But in my case, $val will be a reference until I read the 3rd level,


The post is demonstrating an expression that prints out only elements 1, 3, 5, ... from an array. The demonstration is:

    for (0..10) {
      my @array1 = (1..$_);
      print "$_: >@array1[map 1+2*$_, 0..($#array1-1)/2]<\n";

Note the rare use of $#array1-1. This is identical to @array1-2:

    for (0..10) {
      my @array1 = (1..$_);
      print "$_: >@array1[map 1+2*$_, 0..(@array1-2)/2]<\n";

With this change, we can move the -2 out of the fraction:

    for (0..10) {
      my @array1 = (1..$_);
      print "$_: >@array1[map 1+2*$_, 0.. @array1/2 -1 ]<\n";

This suggests the following transformation:

    for (0..10) {
      my @array1 = (1..$_);
      print "$_: >@array1[map 2*$_-1, 1.. @array1/2 ]<\n";

The behavior is now a lot clearer. You can see at a glance how many elements will be printed out: Exactly half (rounded down). It is much more difficult to see this in the original code.


The author appears to believe that $#a=0 is necessary to initialize a previously unused Perl array to contain zero elements:

        open (IN,"data");
        while (<IN>) {
        push (@a,/\s(nam\S+)/g);
        for $i(@a) {
        print "name     = $i\n";
        print "service  = $serv\n";
In this case, the $#a=0; line is erroneous, since it is inserting an extra undefined item at the start of the array. The bug can be fixed by deleting the entire $#a=0; line.


The author has a list of records, each containing a domain name and a count:

        @array = (['', '46'],
                  ['', '22'],
                  ... );

The user wants to eliminate duplicate domain names and sum the counts for each unique domain. The code presented sorts the array by domain name; then scans the array, comparing each element's domain with the next element's domain.

        @array = sort { $a->[0] <=> $b->[0] } @array;
        $c = 0;
        for($r = 0;$r <= $#array;$r++)
           if($array[$r][0] ne $array[$r+1][0])
             $domains[$c][0] = $array[$r][0];
             $domains[$c][1] += $array[$r][1];
              $domains[$c][0] = $array[$r][0];
              $domains[$c][1] += $array[$r][1];

Note that the code, as presented, may have a bug, because it indexes off the end of the array.

Better code would be:

        my (%seen, %count, @unique_domains);
        for (@array) {
          my ($domain, $count) = @$_;
          push @unique_domains, $domain unless $seen{$domain}++;
          $count{$domain} += $count;
        @domains = map [$_, $count{$_}], @unique_domains;

If it's not necessary to preserve the original order of the array, then:

        my (%count);
        for (@array) {
          my ($domain, $count) = @$_;
          $count{$domain} += $count;
        @domains = map [$_, $count{$_}], keys %count;
In either case, $#array is not required.

Return to: Universe of Discourse main page | Perl Paraphernalia | Classes and Talks Program Repair Shop and Red Flags | Survey of $#array Usage