CSV into hash

2019-06-24 05:01发布

问题:

I have a csv with the first column a label followed by comma separated values:

LabelA,45,56,78,90
LabelB,56,65,43,32
LabelC,56,87,98,45

I'd like the first column (LabelA etc) to be the Key in a hash with the numeric values in an array.

I can read the file into an array or scalar but I'm not sure what to do after that. Suggestions??

Edit: Ok, so it looks like this assigns the value to a key ..but what about the comma delimited numbers in my example? Where are they going? Are they in %hash ? If so could you maybe dumb down your explanation even further? Thanks.

回答1:

Well, let's assume that there are no special characters and so on.

First you open the file:

open my $fh, '<', 'some.file.csv' or die "Cannot open: $!";

Then you read from it in loop:

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

Afterwards, you remove trailing white characters (\n and others):

$line =~ s/\s*\z//;

And split it into array:

my @array = split /,/, $line;

When it's in array, you get first element off the array:

my $key = shift @array;

And store it in hash:

$hash{$key} = \@array;

(\@array means reference to array).

Whole code:

my %hash;
open my $fh, '<', 'some.file.csv' or die "Cannot open: $!";
while (my $line = <$fh>) {
  $line =~ s/\s*\z//;
  my @array = split /,/, $line;
  my $key = shift @array;
  $hash{$key} = \@array;
}
close $fh;


回答2:

Personally, I like the Text::CSV_XS and IO::File module:

use Text::CSV_XS;
use IO::File;

# Usage example:
my $hash_ref = csv_file_hashref('some_file.csv');

foreach my $key (sort keys %{$hash_ref}){
   print qq{$key: };
   print join q{,}, @{$hash_ref->{$key}};
   print qq{\n};
}

# Implementation:
sub csv_file_hashref {
   my ($filename) = @_;

   my $csv_fh = IO::File->new($filename, 'r');
   my $csv = Text::CSV_XS->new ();

   my %output_hash;

   while(my $colref = $csv->getline ($csv_fh))
   {
      $output_hash{shift @{$colref}} = $colref;
   }

   return \%output_hash;
}


回答3:

See perlfunc split and perldsc.

  1. Read each line.
  2. Chomp it.
  3. Split it on commas.
  4. Use the first value in the result as the key to your HoA.
  5. The other values become the array.
  6. Store a ref to the array in the hash under the key.
  7. ...
  8. Profit!!!

Make a hash of array references:

Your data structure should look like this:

my %foo = (
    LabelA => [  2, 3,  56, 78, 90 ],
    LabelB => [ 65, 45, 23, 34, 87 ],
    LabelC => [ 67, 34, 56, 67, 98 ],
);


回答4:

Text::CSV::Hashify

Turn a CSV file into a Perl hash:

# Simple functional interface
use Text::CSV::Hashify;
$hash_ref = hashify('/path/to/file.csv', 'primary_key');

# Object-oriented interface
use Text::CSV::Hashify;
$obj = Text::CSV::Hashify->new( {
        file        => '/path/to/file.csv',
        format      => 'hoh', # hash of hashes, which is default
        key         => 'id',  # needed except when format is 'aoh'
        max_rows    => 20,    # number of records to read; defaults to all
        ... # other key-value pairs possible for Text::CSV
} );

# all records requested
$hash_ref       = $obj->all;


回答5:

I think this can also work easier.

The $refhashvariable will be a reference to an array of hashes.

Each hash contain the headers (as hashkey) and the values of one CSV line. The array contains the hashes for all lines in the CSV.

use Text::CSV_XS qw( csv );
$refhashvariable = csv(
    in      => "$input_csv_filename",
    sep     => ';',
    headers => "auto"
);    # as array of hash

This works for me. I have not tried en case the CSV does not have headers.



标签: perl hash