0

I'm totally new to Perl, and I've been assigned some task... I have to read a tab separated file, and then do some operations with the data in a DB. The .tsv file is like this:

ID Name Date

155 Pedro 1988-05-05

522 Mengano 2002-08-02

So far I thought that creating a multidimensional array with the data of the file will be a good solution to handle this data later. So I read the file line by line, skip the item title columns and save the values in an array. However, I'm having difficulties creating this multidimensional array... this is what I've done so far:

#Read file from path
my @array;
my $fh = path($filename)->openr_utf8;
while (my $line = <$fh>) {
    chomp $line;
    # skip comments and blank lines and title line
    next if $line =~ /^\#/ || $line =~ /^\s*$/ || $line =~ /^\+/ || $line =~ /ID/;
    #split each line into array
    my @aux_line = split(/\s+/, $line);
    push @array, @{ $aux_line };
    }

Obviously, last line is not working... how could be done to create an array of arrays this way? I'm little bit lost with references... And somebody can think of a better way to store this data we read from file? Thank you!

8
  • push @array, \@$aux_line; Commented Feb 20, 2016 at 11:19
  • 1
    I assume this question was answered many times before. Use Text::CSV or Text::CSV::Slurp. It can use the first line as field names, creates an array of hashes with field names as key and is nearly ready for inserting into a database via DBIx::Class if the field names match the column names of the DB. Commented Feb 20, 2016 at 12:57
  • 1
    Another option is to read your data with SQL using DBD::CSV. Commented Feb 20, 2016 at 16:48
  • 1
    @reinierpost just changing this for a " "? csv_sep_char => "," Commented Feb 20, 2016 at 18:39
  • 1
    @ArtanisAce With DBIx::Class you can use $schema->resultset('MyTable')->update_or_create($hashref_of_csv_record); Should fit in your case where you have the IDs in the TSV records. Commented Feb 21, 2016 at 11:36

2 Answers 2

2

You can also do this with map:

use Data::Dumper;
my @stuff = map {[split]} <$fh>;
print Dumper \@stuff;

(with maybe a grep to skip comments)

But it may suit your use case better to use an array of hashes :

my @stuff ;
chomp(my @header = split ' ', <$fh>);
while ( <$fh>)  {
    my %this_row;
    @this_row{@header} = split;
    push ( @stuff, \%this_row) ;
}
Sign up to request clarification or add additional context in comments.

1 Comment

This hash-based solution is almost certainly superior in this case.
1

First, use strict and use warnings. That would instantly alert you about that your wrong way to get array reference tries to access completely different variable (Perl allows variable of different types have same names).

After that just change your last line to:

push @array, \@aux_line;

2 Comments

Oh was trying some stuff but not this! Now I think got the point; passing a reference don't pass any value but just the memory location... that's why when you use 'push' the values of '@array_line' don't get pushed to '@array' right? Thank you very much Oleg!
Pretty much so. On top level you have array filled with references to other arrays.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.