Reputation: 11
I'm trying to write a script that will separate out columns of data from a (not terribly large) .csv into individual lists for use later using the Text::CSV_XS library. I have no problem getting individual columns, but I seem to be unable to iterate through a list of columns using a foreach loop.
#!/usr/bin/perl
use strict;
use warnings;
use Text::CSV_XS;
use 5.18.2;
my $csv = Text::CSV_XS->new ({ binary => 1, auto_diag => 1 });
open my $fh, "<", "/users/whoever/test_csv.csv" or die "$!";
sub column_grabber {
foreach my $column (@_) {
my @data = map { $_->[$column] } @{$csv->getline_all ($fh)};
return @data;
}
}
my @column_numbers = (1,2,3,4);
my @collected_data = column_grabber(@column_numbers);
close $fh or die "$!";
Calling this subroutine for a list of columns gives me only the first column of the list as anticipated, but none of the following columns from the list. A bit of troubleshooting shows that @_ is seeing the entire list I pass.
By omitting the return statement, the foreach loop carries through all of the columns passed in @ids, but I get no output from @data.
Is there some behavior in the loop I'm not accounting for? Perhaps it has something to do with the map() statement?
So after playing around with this for a while and rethinking things a bit, I've solved my problem.
@column_numbers
outside the
subroutine and pass scalars to &column_grabber
instead. This saves
me from getting lost in a sea of references when I don't really need
to worry about it for this small script.So now my functioning script looks like this:
#!/usr/bin/perl
use strict;
use warnings;
use Text::CSV_XS;
use 5.18.2;
sub column_grabber {
my $csv = Text::CSV_XS->new ({ binary => 1, auto_diag => 1 });
open my $fh, "<", "/users/whoever/test_csv.csv" or die "$!";
my $column = shift @_;
my @data = map { $_->[$column] } @{$csv->getline_all ($fh)};
return @data;
close $fh or die "$!";
}
my @column_numbers = (1,2,3,4);
foreach my $column(@column_numbers){
my @collected_data = &column_grabber($column);
...
}
Thanks for the input and help from commenters.
Upvotes: 1
Views: 161
Reputation: 386696
Keep in mind that each element of @data
(hereby renamed @rows
or $rows
) should be a reference to an array of the selected fields.
my @rows;
while ( my $row = $csv->getline($fh) ) {
push @rows, [ @{ $row }[@column_numbers] ];
}
or
my $rows = $csv->getline_all($fh);
@_ = @{ $_ }[@column_numbers] for @$rows;
or
my @rows = map { [ @{ $_ }[@column_numbers] ] } @{ $csv->getline_all($fh) };
Upvotes: 2