my .csv file looks like:
sim_time,a,b,c,d
0,0,0,0,0
12,0,1,1,0
115,1,1,1,1
200,0,0,1,0
I have multiple csv file in which no of rows and column are different .
The output should look like :
sim_time 0 12 115 200
a 0 0 1 0
b 0 1 1 0
c 0 1 1 1
d 0 0 1 0
The code i am trying to use is as follows:
#!/usr/bin/perl
my $file = "report_69.csv";
my $column_separator = ',';
open (my $INFILE, "<" , "$file");
open(my $FILE,">","report_69.txt") or die "$!";
while (<$INFILE>) {
chomp;
my @c = split(',', $_);
my $d = @c;
print $d;
my @columns = split(/$column_separator/);
for( $a = 0; $a < $d; $a = $a 1 ) {
push ("@x_{$a}", $columns[$a] ); # the problem (1)
}
}
The problem (1) arise while defining the array as it is not a valid way to define the array. Is there any other way to do the same.
Now I am facing issue while content of the each column into an array because I can define the multiple array as per need .
CodePudding user response:
The data in the CSV file need be transposed, judged by the shown desired output
use warnings;
use strict;
use feature 'say';
use Text::CSV;
my $file = shift // die "Usage: $0 file\n";
my $csv = Text::CSV->new ({ binary => 1, auto_diag => 2 });
my @data;
open my $fh, $file or die "Can't open $file: $!";
while ( my $row = $csv->getline($fh) ) {
push @data, $row;
}
close $fh;
# Transpose data
my @res;
foreach my $row (@data) {
foreach my $col_n (0 .. $#$row) {
push @{ $res[$col_n] }, $row->[$col_n];
}
}
# Print results
for my $row (@res) {
say "@$row";
}
The syntax $#$name
stands for the last index in an array reference of that name
.
While the shown data is easily parsed by hand† it is always better to entrust the job to a library for CSV and I use the excellent Text::CSV to read the CSV file.
The resulting (transposed) data is printed to STDOUT
and so can be redirected to a file. Or change the last part to print directly to a file.
NOTE The shown input has a missing field in the fourth row (115,1,1,1
) but the shown desired output doesn't, effectively showing a 1
for it. I am ignoring this until clarified, considering it as a typo in posting.
† Even as just
my @data = map { chomp; [ split /\s*,\s*/ ] } <>;
for a file with the name given on the command line (so found in @ARGV
and thus read line by line by <>
). However, as soon as there is anything more interesting in the file -- spaces, newlines, quotes, ... -- we really want a library. So just use a library.
CodePudding user response:
My simplistic answer:
#!/usr/bin/perl
use warnings; use strict;
my $file = "data.txt";
my $column_separator = ',';
open (my $INFILE, "<" , "$file");
my @rows = ();
my $row=0;
while (<$INFILE>) {
chomp;
next if (/^$/);
my @cols = split(",");
for(my $c = 0; $c < scalar @cols; $c ) {
$rows[$c][$row] = "" . $cols[$c];
}
$row ;
}
for my $row(@rows) {
print join(",", @{$row}), "\n";
}
I'm no perl expert, but this seems to tick the box (file handling excepted).