views:

39

answers:

1

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

+1  A: 

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
after you assign from `@_` to the lexicals, the aliasing to the argument list is lost. you need to write `$_[0] = $read[-1];`
Eric Strom
@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
@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
@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
@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
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