4

Specifically, I want to use rcols with the PERLCOLS option.

Here's what I want to do:

my @array;
getColumn(\@array, $file, 4); # get the fourth column from file

I can do it if I use \@array, but for backward compatibility I'd prefer not to do this. Here's how I'd do it using an array-ref-ref:

sub getColumn {

    my ($arefref, $file, $colNum) = @_;    

    my @read = rcols $file, { PERLCOLS => [$colNum] };
    $$arefref = $read[-1];

    return;
}

But, I don't see how to make a subroutine that takes an array ref as an argument without saying something like @$aref = @{$read[-1]}, which, afaict, copies each element individually.

PS: reading the PDL::IO::Misc documentation, it seems like the perl array ought to be $read[0] but it's not.

PERLCOLS - an array of column numbers which are to be read into perl arrays rather than piddles. Any columns not specified in the explicit list of columns to read will be returned after the explicit columns. (default B).

I am using PDL v2.4.4_05 with Perl v5.10.0 built for x86_64-linux-thread-multi

brian d foy
  • 129,424
  • 31
  • 207
  • 592
flies
  • 2,017
  • 2
  • 24
  • 37
  • What happens if you change the `rcols` line to `my @read = rcols $file, $colNum, { PERLCOLS => [$colNum] };`? Does `$read[0]` have the Perl arrayref in it then? – CanSpice Oct 05 '10 at 22:47
  • @CanSpice hrmm, no. it seems like when you do it that way, `@read` still has two elements. – flies Oct 06 '10 at 18:51

2 Answers2

1

I believe part of the difficulty with using rcols here is that the user is running PDL-2.4.4 while the rcols docs version was from PDL-2.4.7 which may have version skew in functionality. With the current PDL-2.4.10 release, it is easy to use rcols to read in a single column of data as a perl array which is returned via an arrayref:

pdl> # cat data
1 2 3 4
1 2 3 4
1 2 3 4

pdl> $col = rcols 'data', 2, { perlcols=>[2] }
ARRAY(0x2916e60)

pdl> @{$col}
3 3 3

Notice that in the current release, the perlcols option allows one to specify the output type of a column rather than just adding a perl-style column at the end.

Use pdldoc rcols or do help rcols in the PDL shell to see the more documentation. A good resource is the perldl mailing list.

chm
  • 147
  • 1
  • 3
1

I don't understand why this wouldn't work:

my $arr_ref;
getColumn( $arr_ref, $file, 4 );

sub getColumn {
  my ( $arr_ref, $file, $colNum ) = @_;

  my @read = rcols, $file, { PERLCOLS => [ $colNum ] };
  # At this point, @read is a list of PDLs and array references.

  $arr_ref = $read[-1];
}

Looking at the rcols() documentation, it looks like if you add the PERLCOLS option it returns whatever column you request as an array reference, so you should be able to just assign it to the array reference you passed in.

And as for the documentation question, what I understand from that is you haven't specified any explicit columns, therefore rcols() will return all of the columns in the file as PDLs first, and then return the columns you requested as Perl arrayrefs, which is why your arrayref is coming out in $read[-1].

CanSpice
  • 34,814
  • 10
  • 72
  • 86
  • 2
    after you assign from `@_` to the lexicals, the aliasing to the argument list is lost. you need to write `$_[0] = $read[-1];` – Eric Strom Oct 06 '10 at 00:16
  • @Eric your comment has answered the question. I tried CanSpice's solution before asking SO. I don't quite understand why `$_[0]` and `$arr_ref` behave differently. – flies Oct 06 '10 at 16:26
  • @flies: `$_[9]` is aliased to the original value, so you can change it directly. `my ($arr_ref, ...) = @_;` makes copies. Otherwise they are the same. – Ether Oct 06 '10 at 18:02
  • @Ether thanks. I never knew that. seems like kind of unsafe behavior for the subroutine always have direct access to its arguments (though a non-issue in the typical `my (...) = @_` and `my $a = shift` idioms). i guess if you wanted all your arguments to be passed by reference you could say something like `my @pbr; push(@pbr, \$_) for @_;`!? – flies Oct 06 '10 at 18:46
  • @flies: (make that `$_[0]` not `$_[9]` of course -- typo) :) And yes, you could pass references -- see `perldoc perlsub` under "Pass By Reference" for more details. – Ether Oct 06 '10 at 18:51
  • 1
    you can even do things like taking a reference to `@_`, then, for the life of that reference, when you dereference its values, you will be interacting with the original argument list. this can come in handy when you are creating closures, and you want the sub to close around the actual arguments and not just copies (for example, if one of the variables in the argument does not get initialized until later) – Eric Strom Oct 06 '10 at 19:53