1

I have a CSV file with the following information seperated by commas ...

Owner,Running,Passing,Failing,Model
D42,21,54,543,Yes
T43,54,76,75,No
Y65,76,43,765,Yes

I want to open this CSV file and place its containments inside of a perl hash in my program. I am also interested in the code needed to print a specific element inside of the has. For example, how I will print the "Passing" count for the "Owner" Y65.

The code I currently have:

$file = "path/to/file";

open $f, '<', $files, or die "cant open $file"

while (my $line = <$f>) {

#inside here I am trying to take the containments of this file and place it into a hash. I have tried numerous ways of trying this but none have seemed to work. I am leaving this blank because I do not want to bog down the visibility of my code for those who are kind enough to help and take a look. Thanks.

}

AS well as placing the csv file inside of a hash I also need to understand the syntax to print and navigate through specific elements. Thank you very much in advance.

5
  • Yes this is easy, but it is expected that you show what you have tried. Please post the code you are struggling with. Please see How to ask for more information Commented Sep 14, 2018 at 20:51
  • 1
    @hakonhagland I posted some code that I have. I didn't post it originally because I did not want to bog down anyone's vision in my incorrect code. Thanks in advance. Commented Sep 14, 2018 at 21:11
  • Ok, the next step is to split each line on comma. You could try use the split function or the more advanced Text::CSV module. Then use the first item (owner) as a hash key and the rest of the items as the value (an array), and save it into an %owners hash... Commented Sep 14, 2018 at 21:16
  • @hakonhagland Thank you for the help. I have tried exactly what you told me but have not been able to reach a solid output. Is it possible you could write some sample code on the problem to push me in the right direction? Any help is greatly appreciated. Thank you very much Commented Sep 14, 2018 at 21:27
  • Consider using CPAN module Text::CSV::Hashify. Commented Sep 15, 2018 at 23:26

2 Answers 2

1

Here is an example of how to put the data into a hash %owners and later (after having read the file) extract a "passing count" for a particular owner. I am using the Text::CSV module to parse the lines of the file.

use feature qw(say);
use open qw(:std :utf8);  # Assume UTF-8 files and terminal output
use strict;
use warnings qw(FATAL utf8);
use Text::CSV;

my $csv = Text::CSV->new ( )
  or die "Cannot use CSV: " . Text::CSV->error_diag ();
my $fn = 'test.csv';
open my $fh, "<", $fn
  or die "Could not open file '$fn': $!";
my %owners;
my $header = $csv->getline( $fh );  # TODO: add error checking 
while ( my $row = $csv->getline( $fh ) ) {
    next if @$row == 0; # TODO: more error checking
    my ($owner, @values) = @$row;
    $owners{$owner} = \@values;
}
close $fh;

my $key = 'Y65';
my $index = 1;
say "Passing count for $key = ", $owners{$key}->[$index];
Sign up to request clarification or add additional context in comments.

3 Comments

@hakonhagland Thank you for the guidance. When implementing your code, I get the output " Use of uninitialized value in say at table.pl line 78. Passing count for Y65 = " Line 78 in this case being the last line of the code. I have been trying to tweak it, but I have not been able to get it to work still. Thank you so much for your guidance thus far.
You should use :encoding(UTF-8) rather than :utf8
@FranceMadrid As line 78 is the last line, the warning "Use of uninitialized value in say at table.pl line 78" means that either $key, $index, or most likely $owners{$key} is undefined. My guess would be that the key $key does not exist in the hash %owners. Can you check that by using e.g. Data::Dumper on the hash?
0

Since it's not really clear what "load a CSV file into a perl hash" means (Nor does it really make sense. An array of hashes, one per row, maybe, if you don't care about keeping the ordering of fields, but just a hash? What are the keys supposed to be?), let's focus on the rest of your question, in particular

how I will print the "Passing" count for the "Owner" Y65.

There are a few other CSV modules that might be of interest that are much easier to use than Text::CSV:

  • Tie::CSV_File lets you access a CSV file like a 2D array. $foo[0][0] is the first field of the first row of the tied file.

So:

#!/usr/bin/perl
use warnings;
use strict;
use feature qw/say/;
use Tie::CSV_File;

my $csv = "data.csv";
tie my @data, "Tie::CSV_File", $csv or die "Unable to tie $csv!";
for my $row (@data) {
  say $row->[2] and last if $row->[0] eq "Y65";
}
  • DBD::CSV lets you treat a CSV file like a table in a database you can run SQL queries on.

So:

#!/usr/bin/perl
use warnings;
use strict;
use feature qw/say/;
use DBI;

my $csv = "data.csv";
my $dbh = DBI->connect("dbi:CSV:", undef, undef,
                       { csv_tables => { data => { f_file => $csv } } })
  or die $DBI::errstr;
my $owner = "Y65";
my $p = $dbh->selectrow_arrayref("SELECT Passing FROM data WHERE Owner = ?",
                                 {}, $owner);
say $p->[0] if defined $p;
  • Text::AutoCSV has a bunch of handy functions for working with CSV files.

So:

#!/usr/bin/perl
use warnings;
use strict;
use feature qw/say/;
use Text::AutoCSV;

my $csv = "data.csv";
my $acsv = Text::AutoCSV->new(in_file => $csv) or die "Unable to open $csv!";
my $row = $acsv->search_1hr("OWNER", "Y65");
say $row->{"PASSING"} if defined $row;

This last one is probably closest to what I think you think you want.

Comments

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.