in reply to Question about returning array from sub

Data::Dumper will help you immeasurably when working with complex data structures.

use Data::Dumper; say Dumper \@rot_mat;

When you did

$rot_mat[0][0]=cos($phi_rad)*cos($theta_rad)*cos($psi_rad)-sin($phi_ra +d)*sin($psi_ +rad);

Perl automagically created an anonymous array as the value of the first element in the array, and assigned your data to the first element of the anonymous array.

You just need to dereference it.

#!/usr/bin/env perl use strict; use warnings; use Data::Dumper; use feature qw/ say /; my @a; $a[0][0] = 'foo'; $a[0][1] = 'bar'; $a[1][0] = 'baz'; $a[1][1] = 'quux'; say Dumper @a; say $a[0]; for ( @a ) { say (join ' ', @{ $_ }); }
[05:58][nick:~/monks]$ perl 1134141.pl $VAR1 = [ 'foo', 'bar' ]; $VAR2 = [ 'baz', 'quux' ]; ARRAY(0x7feb6b006280) foo bar baz quux
Remember: Ne dederis in spiritu molere illegitimi!

Replies are listed 'Best First'.
Re^2: Question about returning array from sub
by QM (Parson) on Jul 10, 2015 at 13:29 UTC
    The Dumper output may be more intuitive if it is passed a reference to the array:
    say Dumper \@a;

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

      This is output of the Dumper -
      $VAR1 = [ [ 1, 0, 0 ], [ 0, 1, 0 ], [ 0, 0, '1' ] ]; $VAR1 = [ [ '0.99985288395361', '-0.0139786208260096', '0.00994025198128738' ], [ '0.0138118911491265', '0.999766001562737', '0.0166485369370161' ], [ '-0.0101706495630081', '-0.0165087939917233', '0.999811991130535' ] ];
        Yes! That's how I expect a 2D array reference to dump. Is that what you expect?

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

        The output is as expected here.
Re^2: Question about returning array from sub
by ojagan (Novice) on Jul 10, 2015 at 13:14 UTC
    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?

      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!
      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?