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.