Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sorting CSV file column value based on column headers

Tags:

perl

Hi am newbie fir perl scripting, i need a help implement a logic for sorting CSV file header based column values,.

Example:

S.NO,NAME,S2,S5,S3,S4,S1
1,aaaa,88,99,77,55,66
2,bbbb,66,77,88,99,55
3,cccc,55,44,77,88,66
4,dddd,77,55,66,88,99

now i want to sort this file as below..

s.no,s2,s4,s5,s1,s0,name => that's how i want is as i defined order of headers like s.no,name,s1,s2,s3,s4,s5 and it's respective whole columns values also should change based on header exchange, how to do it perl this one...?

That's the required output is like following bellow,

S.NO,NAME,S1,S2,S3,S4,S5 1,aaaaaaa,66,88,77,55,99 2,bbbbbbb,55,66,88,77,99 3,ccccccc,66,55,77,88,44 4,ddddddd,99,77,66,88,55

or what the order i want in column headers, like below.

S.NO,NAME,S5,S4,S3,S2,S1 -> like as per my requirement i need to re-order my columns header and it's respective columns value also..

#!/usr/bin/perl


use strict;
use warnings;

use Text::CSV;
my $file = 'a1.csv';

my $size = 3;

my @files;

my $csv = Text::CSV->new ({ binary => 1, auto_diag => 1, sep_char => ';' });
open my $in, "<:encoding(utf8)", $file or die "$file: $!";
while (my $row = $csv->getline($in)) {
    if (not @files) {
        my $file_counter = int @$row / $size;
        $file_counter++ if @$row % $size;
        for my $i (1 .. $file_counter) {
            my $outfile = "output$i.csv";
            open my $out, ">:encoding(utf8)", $outfile or die "$outfile: $!";
            push @files, $out;
        }
    }

    my @fields = @$row;
    foreach my $i (0 .. $#files) {
        my $from = $i*$size;
        my $to   = $i*$size+$size-1;

        $to      = $to <= $#fields ? $to : $#fields;
        my @data = @fields[$from .. $to];

        $csv->print($files[$i], \@data);
        print {$files[$i]} "\n";
    }
}
like image 706
Shanmugam E Avatar asked Jul 15 '26 16:07

Shanmugam E


2 Answers

#!/usr/bin/perl
use strict;
use warnings;
use autodie;
use Text::CSV qw();
my @headers = qw(s.no name s1 s2 s3 s4 s5);
my $csv_in = Text::CSV->new({binary => 1, auto_diag => 1});
my $csv_out = Text::CSV->new({binary => 1, auto_diag => 1});
open my $in, '<:encoding(UTF-8)', 'a1.csv';
open my $out, '>:encoding(UTF-8)', 'output1.csv';
$csv_in->header($in);
$csv_out->say($out, [@headers]);
while (my $row = $csv_in->getline_hr($in)) {
    $csv_out->say($out, [$row->@{@headers}]);
}
like image 67
daxim Avatar answered Jul 17 '26 16:07

daxim


The handy Text::AutoCSV module lets you rearrange the column order as a one-liner:

$ perl -MText::AutoCSV -e 'Text::AutoCSV->new(in_file=>"in.csv",out_file=>"out.csv",out_fields=>["SNO","NAME","S1","S2","S3","S5"])->write()'
$ cat out.csv
s.no,name,s1,s2,s3,s5
1,aaaa,66,55,77,99
2,bbbb,55,99,88,77
3,cccc,66,88,77,44
4,dddd,99,88,66,55

I'm not sure what your actual desired order of fields is because you have two and both of them include columns that aren't in the sample input file (It has two s2 columns; is one of them supposed to be s4?), but you should get the idea. Column names have to be all caps with special characters like . removed, but the actual names are used for the output.

like image 27
Shawn Avatar answered Jul 17 '26 16:07

Shawn