Followers

Tuesday, October 19, 2021

A dangerous $# in perl arrays - Not recommended for iteration

 The innocent looking $# operator that we often use for determining the maximum index of an array in for loop can be sometimes dangerous.

I spent a sizable amount of time wondering why my for loop is becoming an infinite loop without realizing that writing something like this actually changes the max index value or $# value of an array

Say you have 2 dimensional array @sorted and you want to print the component. The easiest way would be:

for(my $i=0; $i <= $#sorted; $i++){

                for(my $j=0; $j <= @{$sorted[$i]}; $j++){

                        print "$sorted[$i][$j]\t";

                        }

                        print "$#sorted\n";

        }


The output will be a neat:


3349    4097    gene-PR001_g8806                9 ----> The last column indicates the max index 

6662    6832    gene-PR001_g8807                9

11316   11696   gene-PR001_g8808                9

13158   13334   gene-PR001_g8809                9

18688   19095   gene-PR001_g8810                9

25175   25342   gene-PR001_g8811                9

26554   26883   gene-PR001_g8812                9

28100   29059   gene-PR001_g8813                9

29128   30235   gene-PR001_g8814                9

30266   30786   gene-PR001_g8815                9


Here one can notice the value of the last column is that of the max index of the array that remains unchanged and hence the lop terminates.

However, something as innocent as a c style this involving accessing the $i+1 element of the array actually changes  the array maximum index!! This came as a surprise to me where I hit the infinite loop leading to out of memory and locked file alert.

Check this out::

for(my $i=0; $i <= $#sorted; $i++){

                for(my $j=0; $j <= @{$sorted[$i]}; $j++){

                        print "$sorted[$i+1][$j]\t";---> Accessing the $i+1 value rather than $i value

                        }

                print "$#sorted\n";

                }

Here all the hell breaks loose where you hit a infinite loop when you suspect the least. Therefore, it
will be prudent to first pass the value of $#sorted to a variable and loop over that value instead of looping directly over $#sorted.

3349    4097    gene-PR001_g8806                9 

6662    6832    gene-PR001_g8807                9

11316   11696   gene-PR001_g8808                9

13158   13334   gene-PR001_g8809                9

18688   19095   gene-PR001_g8810                9

25175   25342   gene-PR001_g8811                9

26554   26883   gene-PR001_g8812                9

28100   29059   gene-PR001_g8813                9

29128   30235   gene-PR001_g8814                9

30266   30786   gene-PR001_g8815                9

10

11

... --> Increases infinitely!


A potentially dangerous infinite loop where you are least suspicious!!!

A neat solution for this problem will be:

my $index = $#sorted;--> notice this statement

        for(my $i=0; $i <= $index; $i++){

                for(my $j=0; $j <= @{$sorted[$i]}; $j++){

                        print "$sorted[$i+1][$j]\t";

                        }

                print "$#sorted\n";

                }



6662    6832    gene-PR001_g8807                9

11316   11696   gene-PR001_g8808                9

13158   13334   gene-PR001_g8809                9

18688   19095   gene-PR001_g8810                9

25175   25342   gene-PR001_g8811                9

26554   26883   gene-PR001_g8812                9

28100   29059   gene-PR001_g8813                9

29128   30235   gene-PR001_g8814                9

30266   30786   gene-PR001_g8815                9

10 --> Notice this 10 below. 

This means that the value of index is on rise but the loop terminates nevertheless!! Is this a bug in perl??