How to fetch values of sub array present in array - loops

I have created one array and pushing another array in each iteration of loop into it. Once it will be done I wanted to fetch the values of each sub array as well as array.
Code I am using :
my $i;
my #carrierValuesAll="";
while (my #row = $sth->fetchrow_array()) {
my #carrierValues=join(',', #row). "\n";
push(#carrierValuesAll, #carrierValues);
}
$len = #carrierValuesAll;
for ($i = 0; $i < $len; $i = $i + 1) {
print ("\#carrierValuesAll[$i] = $carrierValuesAll[$i]\n");
print("\n");
}
The output I am getting is :
#carrierValuesAll[1] = 1,1,https://au-sbc.trustidinc.com/tid,sbcLabStub,sbcLab,,SKY,0,2019-11-07 20:10:43,2021-07-02 04:39:43,TrustID Lab Oracle,Y,Y,Y,ivr.localdomain,Y,trustid
#carrierValuesAll[2] = 2,1,https://au-sbc.trustidinc.com/tid,sbcLab,sbcLab,,SKY,2,2019-11-07 20:10:43,2020-12-14 06:24:17,TrustID Lab Oracle,Y,Y,Y,ivr.localdomain,Y,admin
What I have tried :
$len = #carrierValuesAll;
for ($i = 0; $i < $len; $i = $i + 1) {
print ("\#carrierValuesAll[$i] = $carrierValuesAll[$i]\n");
print("\n");
for (my $j=0;$j<$carrierValuesAll[$i];$j++) {
print("\#carrierValuesAll[$j] = $carrierValuesAll[$j]\n");
print("\n");
}
}
added one more nested loop into it, but it wont helped.
This output is what coming from database & I am trying to store it in array.

You only have one array here - well you have a second array variable, but you only ever store a single, scalar value in it.
Let's look at your code:
my $i;
my #carrierValuesAll="";
Declaring $i so far away from where it is used is a bit of a code smell. It'll work fine, of course, but Perl gives you the flexibility to declare variables where you use them - so use it.
And #carrierValuesAll="" isn't doing what you think it's doing. I suspect you think it's declaring an empty array. But actually it creates an array containing a single element which is an empty string.
while (my #row = $sth->fetchrow_array()) {
my #carrierValues=join(',', #row). "\n";
push(#carrierValuesAll, #carrierValues);
}
You now declare a new array, #carrierValues, but you give it a value which is returned from join(). The whole point of join() is to take a list of values (your data in #row) and join it together into a single string. You then push that single string onto the end of #carrierValuesAll.
There is no point in storing the result from join() in an array. The result from join() is only ever a single, scalar value.
So after this loop has finished running, you have an array, #carrierValuesAll which contains one of these single strings for each of the rows in your database table. There are no "subarrays" here. Just an array of strings.
You then confirm that by printing the contents of #carrierValuesAll.
$len = #carrierValuesAll;
for ($i = 0; $i < $len; $i = $i + 1) {
print ("\#carrierValuesAll[$i] = $carrierValuesAll[$i]\n");
print("\n");
}
And that prints exactly what I would expect. You get the data that you read from the database separated by commas.
If you don't want a single string, then don't use join() to make one. Instead, take a copy of #row and store a reference to that in your array:
while (my #row = $sth->fetchrow_array()) {
push(#carrierValuesAll, [ #row ]);
}
I'm not sure what you want to do with your array of arrays, but here's how you could print it out:
$len = #carrierValuesAll;
for (my $i = 0; $i < $len; $i = $i + 1) {
print ("\#carrierValuesAll[$i] = #{$carrierValuesAll[$i]}\n");
print("\n");
}
Note that I've used #{$carrierValuesAll[$i]} to dereference the array reference stored at $carrierValuesAll[$i] and turn it back into an array which I can then print.
Note also that I've moved the declaration of $i into the for loop where it makes more sense.
But most Perl programmers wouldn't use this "C-style" for loop as it looks horrible and is harder to understand. I would write this code as:
for my $i (0 .. $#carrierValuesAll) {
...
}
Instead of calculating the length of the array and then remembering to stop one iteration before reaching that, I've used the special variable $#ARRAY which gives me the index of the last index in the array.

Related

how to get the number of elements in a 2D array in Perl

I am working with a 2D array in Perl, and have come across a stumbling block, that I am hoping someone can help me with.
I am reading a file that has x number of lines and y number of columns, this I am placing into a 2D array,
for testing purposes I am trying to print out the contents of the first element(line) in the array using a for loop:
for( $m = 0; $m <= $#fields; $m++)
{
printf "Field [0][$m] = $fields[0][$m]\n";
}
The problem I am running into is that this loops for the entire size of array rather then the length of the 2nd element.
Any help will be appreciated.
Use the $#{} dereference to get the last index of an array reference:
for (my $m = 0; $m <= $#{ $fields[0] }; $m++)

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

How to get around the scope of the foreach loop in Perl

So I'm working through a bit of code that my compiler really doesn't like. There are two arrays, that have an identical number of indexes. #array is populated with 0's, #otherarray is populated sequentially. In this foreach loop, it skips over the first value because it is filled outside the loop. Count is declared as 1 outside the loop as well.
foreach (#array) {
if ($count == 1) {
} elsif($_ == 0 && #otherarray[$count-1] != undef) {
$_ = $count;
splice(#otherarray, #otherarray[$count - 1], 1);
} else {
$_ = $otherarray[ rand #otherarray ];
}
$count++
}
It insists that I have use of uninitialized value in numeric ne(!=) on this line, and every line in which other array is inside an else/if/elsif statement:
elsif($_ == 0 && #otherarray[$count-1] != undef)
How do I work around this? I'm sure it's obvious but I'm really new to Perl, so I'm probably setting something up wrong in the first place? I have already declared my #otherarray.
It is the undef in the comparison which is uninitialized. Use defined instead of comparing to undef:
elsif($_ == 0 && defined($otherarray[$count-1]))

How do I multiply more than two matrices in perl?

I am sending in an array of references and here is my subroutine:
sub multiply
{
my #product;
my $ref1 = $_[0];
my $ref2 = $_[1];
my #array1 = #$ref1;
my #array2 = #$ref2;
}
my ($rowsA,$columnsA) = &dimensions(#$ref1);
my ($rowsB,$columnsB) = &dimensions(#$ref2);
for $i (0..$rowsA-1){
for $j (0..$columnsB-1){
for $k (0..$columnsA-1){
$product[$i][$j] += $array1[$i][$k] * $array2[$k][$j];
}
}
}
This subroutine works for two parameters, but how do I multiply the matrices when more than two parameters are sent?
You want to use the #_ array directly. You won't be able to assign your references directly as you have in your example b/c as you have found, you don't know the number of items being passed. The good thing is, you don't need too. All arguments are passed to Perl sub-routines via the special #_ array. When you see my $x = shift; this array is where the data is being shifted from into your local variables. Here, since you can't know ahead of time how many vars to create, you can use the array directly. Typical array functions apply. (i.e. to get size you can use scalar(#_))
The following example displays the type of sub-routine you would write using regular scalars. It would be the same for references, you would just need to dereference them prior to their use.
#!/usr/bin/perl
my $result = multiply(2,4,5);
print "Result 1: $result\n";
$result = multiply(2,2);
print "Result 2: $result\n";
$result = multiply(2,2,3,5,6);
print "Result 3: $result\n";
sub multiply
{
my $ans = 1;
foreach my $x (#_) { $ans *= $x; }
return $ans;
}
To be combined with RC's answer, which explains what #_ is and how to use it, you can also recurse:
sub multiply {
return $_[0] * $_[1] if #_ <= 2;
return shift( #_ ) * multiply( #_ );
}
It won't be as fast as his answer, but for more complex tasks, can be easier to implement.

How do I create an array of hashes and loop through them in Perl?

I'm trying to create an array of hashes, but I'm having trouble looping through the array. I have tried this code, but it does not work:
for ($i = 0; $i<#pattern; $i++){
while(($k, $v)= each $pattern[$i]){
debug(" $k: $v");
}
}
First, why aren't you useing strict and warnings? The following lines should be at the top of every Perl program you create, right after #!/usr/bin/perl. Always.
use strict;
use warnings;
And I know you aren't because I'm pretty sure you'd get some nice error messages out of strict and warnings from this, and from many other places in your code as well, judging by your variable use.
Second, why aren't you doing this:
for my $i (#pattern) {
..
}
That loops through every element in #pattern, assigning them to $i one at a time. Then, in your loop, when you want a particular element, just use $i. Changes to $i will be reflected in #pattern, and when the loop exits, $i will fall out of scope, essentially cleaning up after itself.
Third, for the love of Larry Wall, please declare your variables with my to localize them. It's really not that hard, and it makes you a better person, I promise.
Fourth, and last, your array stores references to hashes, not hashes. If they stored hashes, your code would be wrong because hashes start with %, not $. As it is, references (of any kind) are scalar values, and thus start with $. So we need to dereference them to get hashes:
for my $i (#pattern) {
while(my($k, $v) = each %{$i}) {
debug(" $k: $v");
}
}
Or, your way:
for (my $i = 0; $i<#pattern; $i++) { # added a my() for good measure
while(my($k, $v) = each %{$pattern[$i]}) {
debug(" $k: $v");
}
}
Try this instead:
for my $hashref (#pattern) {
for my $key (keys %$hashref) {
debug "$key: $hashref->{$key}";
}
}
The biggest problem with what you were trying was each $pattern[$i]. The each function expects a hash to work on, but $pattern[$i] returns a hashref (i.e. a reference to a hash). You could fix your code by dereferencing $pattern[$i] as a hash:
while(my($k, $v) = each %{$pattern[$i]}) {
Also, beware of the each function, it can leave the hash iterator in an incomplete state.
See the documentation for the perl data structures cookbook:
perldoc perldsc

Resources