in reply to Re: Question about returning array from sub
in thread Question about returning array from sub

That indeed showed me the values as expected. So, in the case of a 2D array, the return statement returns the array of array of references instead of the array of array of values. Is that right? If so, I need some advice because I then use this 2D array as input to the next sub which multiplies two matrices. I show part of the main code and sub code below -
@rot_mat1=eul2mat($data_doc1[$i],$data_doc1[$i+1],$data_doc1[$i+2]); @rot_mat2=eul2mat($data_doc2[$i],$data_doc2[$i+1],$data_doc2[$ +i+2]); @cbn_mat=mat_multiply(\@rot_mat1,\@rot_mat2); sub eul2mat { my $phi_rad=deg2rad($_[0]); my $theta_rad=deg2rad($_[1]); my $psi_rad=deg2rad($_[2]); print "$phi_rad $theta_rad $psi_rad\n"; my @rot_mat; $rot_mat[0][0]=cos($phi_rad)*cos($theta_rad)*cos($psi_rad)-sin +($phi_rad)*sin($psi_rad); $rot_mat[0][1]=cos($phi_rad)*cos($theta_rad)*sin($psi_rad)+sin +($phi_rad)*cos($psi_rad); $rot_mat[0][2]=-cos($phi_rad)*sin($theta_rad); $rot_mat[1][0]=-sin($phi_rad)*cos($theta_rad)*cos($psi_rad)-si +n($psi_rad)*cos($phi_rad); $rot_mat[1][1]=-sin($phi_rad)*cos($theta_rad)*sin($psi_rad)+co +s($phi_rad)*cos($psi_rad); $rot_mat[1][2]=sin($phi_rad)*sin($theta_rad); $rot_mat[2][0]=sin($theta_rad)*cos($psi_rad); $rot_mat[2][1]=sin($theta_rad)*sin($psi_rad); $rot_mat[2][2]=cos($theta_rad); say Dumper @rot_mat; return \@rot_mat; } sub mat_multiply { my ($mat1,$mat2)=@_; my ($i,$j,$k); my $result_mat=[]; for $i (0..2) { for $j (0..2) { for $k (0..2) { $result_mat->[$i][$j]+=$mat1->[$i][$k] + * $mat2->[$k][$j]; } } } return $result_mat; }
So I return the array of array of references in the first two lines. But I need to pass these two arrays to the next sub. Am I making a mistake there?

Replies are listed 'Best First'.
Re^3: Question about returning array from sub
by 1nickt (Canon) on Jul 10, 2015 at 14:19 UTC

    You still don't quite have the concepts. There is only a "2-D array" in Perl. See a post from today from Monk::Thomas with some awesome ASCII art depicting Perl arrays.

    At the end you said: I return the array of array of references ...

    Should be: "the array of array references" or "the array of arrayrefs" or "the array of references to arrays" ...

    As for your latest code: (first I would recommend testing with a minimal script like the one I posted above. Then when you have it figured out, start plugging your own code/data back in)

    (for each of two ...)
    • In your first sub you create an actual array eg:
      @rot_mat
    • You populate the array with anonymous arrays containing your data eg:
      $rot_mat[0][0] = 'foo';
    • You return a reference to the main array (to save memory) eg:
      return \@rot_mat;
    • The second sub gets the arrayref by calling the first sub eg:
      my $aref = &first_sub();
    • Second sub really wants the data in the second level of the arrayref. That data is stored in the series of anonymous arrays that compose the first level of the arrayref. So, to access the data we have to access the anonymous arrays, which we do through references to them. eg:
      my $bar = $aref->[0]->[0]; # hard to read
    • Depending on what we are doing, we might copy the anonymous arrays into new arrayrefs inside the second sub (still just pointers to the original in-memory array) eg:
      my $baz = $aref->[0]; my $quux = $aref->[1]; # now $baz is a reference to the anonymous array Perl created # for the first element of @rot_mat when you assigned a value # to $rot_mat[0][0] in the first sub say 'yep' if $baz->[0] eq 'foo';
    • Or maybe just do a double loop to get at the data eg:
      foreach my $anon_array ( @{ $aref } ) { # dereference the main array foreach my $value ( @{ $anon_array } ) { # dereference the anon arra +y say 'yep' if $value eq 'foo'; } }
    • TMTOWTDI

    Hope this helps.

    Remember: Ne dederis in spiritu molere illegitimi!
Re^3: Question about returning array from sub
by QM (Parson) on Jul 10, 2015 at 13:36 UTC
    Warning: I haven't checked the matrix multiply closely, but it looks OK.

    If you are returning a reference from eul2mat, catch it in a scalar:

    $rot_mat1 = eul2mat(...); $rot_mat2 = eul2mat(...); # Notice the scalar here too, since mat_multiply returns a ref: $cbn_mat = mat_multiply($rot_mat1,$rot_mat2);

    (You can still catch it in an @array, but only the first element is defined.)

    -QM
    --
    Quantum Mechanics: The dreams stuff is made of

      Just changed the code -
      $rot_mat1=eul2mat($data_doc1[$i],$data_doc1[$i+1],$data_doc1[$i+2]); +#Catch the reference to the first matrix $rot_mat2=eul2mat($data_doc2[$i],$data_doc2[$i+1],$data_doc2[$ +i+2]); #Catch the reference to the second matrix $cbn_mat=mat_multiply($rot_mat1,$rot_mat2); #Multiply the two +matrices @cbn_angles=mat2eul($cbn_mat); #Convert the matrix back to eul +er sub eul2mat { my $phi_rad=deg2rad($_[0]); my $theta_rad=deg2rad($_[1]); my $psi_rad=deg2rad($_[2]); #print "$phi_rad $theta_rad $psi_rad\n"; my @rot_mat; $rot_mat[0][0]=cos($phi_rad)*cos($theta_rad)*cos($psi_rad)-sin +($phi_rad)*sin($psi_rad); $rot_mat[0][1]=cos($phi_rad)*cos($theta_rad)*sin($psi_rad)+sin +($phi_rad)*cos($psi_rad); $rot_mat[0][2]=-cos($phi_rad)*sin($theta_rad); $rot_mat[1][0]=-sin($phi_rad)*cos($theta_rad)*cos($psi_rad)-si +n($psi_rad)*cos($phi_rad); $rot_mat[1][1]=-sin($phi_rad)*cos($theta_rad)*sin($psi_rad)+co +s($phi_rad)*cos($psi_rad); $rot_mat[1][2]=sin($phi_rad)*sin($theta_rad); $rot_mat[2][0]=sin($theta_rad)*cos($psi_rad); $rot_mat[2][1]=sin($theta_rad)*sin($psi_rad); $rot_mat[2][2]=cos($theta_rad); say Dumper \@rot_mat; return \@rot_mat; } sub mat_multiply { my ($mat1,$mat2)=@_; my ($i,$j,$k); my $result_mat=[]; for $i (0..2) { for $j (0..2) { for $k (0..2) { $result_mat->[$i][$j]+=$mat1->[$i][$k] + * $mat2->[$k][$j]; } } } return $result_mat; } sub mat2eul { print "$_[2][0]\n"; my $theta_deg=rad2deg(atan2((sqrt($_[2][0]**2+$_[2][1]**2)),$_ +[2][2])); my $phi_deg=rad2deg(atan2(($_[1][2]/sin(deg2rad($theta_deg))), +(-$_[0][2]/sin(deg2rad($theta_deg))))); my $psi_deg=rad2deg(atan2(($_[2][1]/sin(deg2rad($theta_deg))), +($_[2][0]/sin(deg2rad($theta_deg))))); return ($theta_deg,$phi_deg,$psi_deg); }
      I now have a bunch of uninitialized values error in the sub mat2eul. My guess is it is most probably because of the way I am accessing the values from $_. What do you think?

        It's gonna throw that warning whenever $_[2][0] is undefined, i.e. didn't get a true value when the array in $_ was created.

        Your code is getting hard to read with all the long variables and math functions, which don't have to do with you understanding the issue (so you'll know how to do it next time). Please reduce to a minimal test case using minimal values and structures to stand in for your, until you have the functionality as you want it. Then plug your data/logic back in.

        Remember: Ne dederis in spiritu molere illegitimi!