Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Write to a CSV file from a hash perl

Tags:

csv

hash

perl

I have a program that at the moment reads from FILE 1 looking like the one below and matching certain characters. e.g

Type, Fruit, Description, quantity
tropical, banana, tasty and yummy, 5
tropical, grapefruit, bitter and not yummy, 2
... and so on

First of all I wanted to create hash of hashes for each 'Type', 'Fruit', 'Description', 'Quantity' and store the different values in the reference hashes. That works fine with the code below.

use strict;
use warnings;
use Data::Dumper;
use Text::CSV;

my %MacroA = ('Type' => {}, 'Fruit' => {}, 'Description' => {}, 'Quantity' =>  {});         

open (my $file, '<', 'FRUITIES.txt') or die $!;     

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

if ($line =~ /\b(tropical)\b,/) {                                   
$MacroA{Type}->{$1}++;
}

if ($line =~ /,\b(banana|grapefruit)\b,/) {                             
$MacroA{Fruit}->{$1}++;
}

if ($line =~ /,([\w\s]+?),/) {                                  
$MacroA{Description}->{$1}++;
}

if ($line =~ /,([\d]+?)/) {                             
$MacroA{Quantity}->{$1}++;
}
        }

close $file;                    

So my question is How can I put this data(data is not fixed) into a csv file or anything related(maybe xls), that would be a table with columns for each hash of hashes ('Type', 'Fruit', 'Description', 'Quantity').

like image 763
El_Commandantee Avatar asked Nov 27 '12 16:11

El_Commandantee


People also ask

How do I push a hash in Perl?

To append a new value to the array of values associated with a particular key, use push : push @{ $hash{"a key"} }, $value; The classic application of these data structures is inverting a hash that has many keys with the same associated value. When inverted, you end up with a hash that has many values for the same key.

How do I read a column from a CSV file in Perl?

To read a column from csv for this purpose I wrote this script: #!/usr/bin/perl -w use strict; use warnings; use Text::CSV; my$column_separator = qr/,/; my $column_number = "3"; my$file = "/home/Admin/Documents/new (copy).


2 Answers

I agree that hashes of hashes is a good thing, but I think you're not storing it in a way you can retrieve it easily.

One way you could do it is like this.

{ id_1 => {
             data_1 => "blah",
             data_2 => "foo",
             ...
           },
  id_2 => {
             ...
           },
  ...
 }

First of all, you need to pick which column would be the "ID". This would determine the uniqueness of each ROW. Let's say for your example let's pick the fruit, since we're assuming there would be no two fruits that would appear in the same file. So we would have something like this:

{ banana => {
             type => "tropical",
             description => "tasty and yummy",
             ...
           },
  grapefruit => {
             ...
           },
  ...
 }

In order to change this back to CSV, we loop through the hashes.

my %fruit_data; #let's assume that this already has the data in it

foreach my $fruit ( keys %fruit_data ) { 

    #given the $fruit you can now access all the data you need
    my $type = %fruit_data{$fruit}{'type'};
    my $desc = %fruit_data{$fruit}{'description'};
    # etc...

    # then you may want to store them in a scalar in any order you want
    my $row = "$field,$type,$desc etc.\n";

    # then work your way from there

}
like image 198
the_qbf Avatar answered Sep 16 '22 11:09

the_qbf


For writing Excel files - you could use Spreadsheet::WriteExcel.

About CSV files - originally you have the CSV-file with "," delimiter and "\n" string delimiters. If you want to write some array of hashrefs to CSV - better way to write down simple sub by yourself, smth like this one:

use strict;
use warnings;

sub write_csv {

  my ($array_ref, $fh) = @_;

  for my $row (@$array_ref) {
    print $fh join(',', map { $_, $row->{$_} } sort keys %$row), "\n";
  }
}

my $test = [
  {a => 1, ab => 2, type => '234k', count => '123'}, 
  {a => 3, ab => 2, type => 'some_type', count => 34},
];

open my $fh, '>', 'test.csv' or die $!;

write_csv($test, $fh);
like image 42
moonsly Avatar answered Sep 17 '22 11:09

moonsly