简体   繁体   中英

Dereferencing an array from an array of arrays in perl

I have various subroutines that give me arrays of arrays. I have tested them separately and somehow when i write my main routine, I fail to make the program recognize my arrays. I know it's a problem of dereferencing, or at least i suspect it heavily.

The code is a bit long but I'll try to explain it:

my @leaderboard=@arrarraa; #an array of arrays
my $parentmass=$spect[$#spect]; #scalar

while (scalar @leaderboard>0) {
        for my $i(0..(scalar @leaderboard-1)) {
        my $curref=$leaderboard[$i]; #the program says here that there is an uninitialized value. But I start with a list of 18 elements.
        my @currentarray=@$curref; #then i try to dereference the array
        my $w=sumaarray (@currentarray);
        if ($w==$parentmass) {
            if (defined $Leader[0]) {
                my $sc1=score (@currentarray);
                my $sc2=score (@Leader);
                if ($sc1>$sc2) {
                    @Leader=@currentarray;
                }

            }
            else {@Leader=@currentarray;}
        }
        elsif ($w>$parentmass) {splice @leaderboard,$i,1;} #here i delete the element if it doesn't work. I hope it's done correctly.

    }
    my $leadref= cut (@leaderboard); #here i take the first 10 scores of the AoAs
    @leaderboard = @$leadref;
    my $leaderef=expand (@leaderboard); #then i expand the AoAs by one term
    @leaderboard= @$leaderef;            #and i should end with a completely different list to work with in the while loop
}   

So I don't know how to dereference the AoAs correctly. The output of the program says:

"Use of uninitialized value $curref in concatenation (.) or string at C:\\Algorithms\\22cyclic\\cyclospectrumsub.pl line 183. Can't use an undefined value as an ARRAY reference at C:\\Algorithms\\22cyclic\\cyclospectrumsub.pl line 184."

I would appreciate enormously any insight or recommendation.

The problem is with the splice that modifies the list while it is being processed. By using the 0..(scalar @leaderboard-1) you set up the range of elements to process at the beginning, but when some elements are removed by the splice , the list ends up shorter than that and once $i runs off the end of the modified list you get undefined references.

A quick fix would be to use

for (my $i = 0; $i < @leaderboard; $i++) 

although that's neither very idiomatic nor efficient. Note that doing something like $i < @leaderboard or @leaderboard-1 already provides scalar context for the array variable, so you don't need the scalar() call, it does nothing here.

I'd probably use something like

my @result;
while(my $elem = shift @leaderboard) {
    ...
    if ($w==$parentmass) {
        # do more stuff
        push @result, $elem;
    }
}

So instead of deleting from the original list, all elements would be taken off the original and only the successful (by whatever criterion) ones included in the result.

There seem to be two things going on here

  • You're removing all arrays from @leaderboard whose sumaarray is greater than $parentmass

  • You're putting in @Leader the array with the highest score of all the arrays in @leaderboard whose sumaarray is equal to $parentmass

I'm unclear whether that's correct. You don't seem to handle the case where sumaarray is less than $parentmass at all. But that can be written very simply by using grep together with the max_by function from the List::UtilsBy module

use List::UtilsBy 'max_by';


my $parentmass = $spect[-1];

my @leaderboard = grep { sumaarray(@$_) <= $parentmass } @arrarraa;

my $leader = max_by { score(@$_) }
        grep { sumaarray(@$_) == $parentmass }
        @leaderboard;

I'm sure this could be made a lot neater if I understood the intention of your algorithm; especially how those elements with a sumarray of less that $parentmass

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM