0

Actually in this assignment, I need to combine 12 input file datas into only one output file. Each input file like this,

ACME A  0   2
ACME A  1   0
ACME A  2   0
ACME A  3   0
ACME A  4   0
ACME A  5   0
ACME A  6   0

In output file ı want to obtain, all related data like this;

**********************************************************************
2017-02-03 0 ACME A 0   2   4   43  4   4   25  4   3   26  4   4   18
2017-02-03 0 ACME A 0   2   4   43  4   4   25  4   3   26  4   4   0
2017-02-03 0 ACME A 0   2   4   43  4   4   25  4   3   26  4   4   0
2017-02-03 0 ACME A 0   2   4   43  4   4   25  4   3   26  4   4   1

Here is my full code.

#! /usr/bin/perl -w

#compiler profilleri
use strict;
use warnings;

sub trim($)
{
my $string = shift;
$string =~ s/^\s+//;
$string =~ s/\s+$//;
return $string;
}

#dosya locationları

my $input_file="C:/Perl64/output/sbc_cause_comp_intraday_2017-02-03_00_01.txt";
my $input_file1="C:/Perl64/output/sbc_cause_comp_intraday_2017-02-03_00_06.txt";
my $input_file2="C:/Perl64/output/sbc_cause_comp_intraday_2017-02-03_00_11.txt";
my $input_file3="C:/Perl64/output/sbc_cause_comp_intraday_2017-02-03_00_16.txt";
my $input_file4="C:/Perl64/output/sbc_cause_comp_intraday_2017-02-03_00_21.txt";
my $input_file5="C:/Perl64/output/sbc_cause_comp_intraday_2017-02-03_00_26.txt";
my $input_file6="C:/Perl64/output/sbc_cause_comp_intraday_2017-02-03_00_31.txt";
my $input_file7="C:/Perl64/output/sbc_cause_comp_intraday_2017-02-03_00_36.txt";
my $input_file8="C:/Perl64/output/sbc_cause_comp_intraday_2017-02-03_00_41.txt";
my $input_file9="C:/Perl64/output/sbc_cause_comp_intraday_2017-02-03_00_46.txt";
my $input_file10="C:/Perl64/output/sbc_cause_comp_intraday_2017-02-03_00_51.txt";
my $input_file11="C:/Perl64/output/sbc_cause_comp_intraday_2017-02-03_00_56.txt";

my $output_file="C:/Perl64/output/denemecik.txt";

#komutlar######
my $ne;  my @cc_type; my @cc_count;
my @cc_count1; my @cc_count2; my @cc_count3; my @cc_count4; my @cc_count5;
my @cc_count6; my @cc_count7; my @cc_count8; my @cc_count9; my @cc_count10; my @cc_count11;
my @total; my $i;

my @count=0; my @count1=0; my @count2=0; my @count3=0; my @count4=0; my @count5=0; my @count6=0;
my @count7=0; my @count8=0; my @count9=0; my @count10=0; my @count11=0;

my $date='sbc_cause_comp_intraday_2017-02-03_00_01';
my $date1=substr($date,24,10);
my $hour=substr($date,35,1);
#print ($hour);

open INPUT, "< $input_file" or die "$0: open of $input_file failed, error: $! \n";
open INPUT1, "< $input_file1" or die "$0: open of $input_file1 failed, error: $! \n";
open INPUT2, "< $input_file2" or die "$0: open of $input_file2 failed, error: $! \n";
open INPUT3, "< $input_file3" or die "$0: open of $input_file3 failed, error: $! \n";
open INPUT4, "< $input_file4" or die "$0: open of $input_file4 failed, error: $! \n";
open INPUT5, "< $input_file5" or die "$0: open of $input_file5 failed, error: $! \n";
open INPUT6, "< $input_file6" or die "$0: open of $input_file6 failed, error: $! \n";
open INPUT7, "< $input_file7" or die "$0: open of $input_file7 failed, error: $! \n";
open INPUT8, "< $input_file8" or die "$0: open of $input_file8 failed, error: $! \n";
open INPUT9, "< $input_file9" or die "$0: open of $input_file9 failed, error: $! \n";
open INPUT10, "< $input_file10" or die "$0: open of $input_file10 failed, error: $! \n";
open INPUT11, "< $input_file11" or die "$0: open of $input_file11 failed, error: $! \n";

open OUTPUT, "> $output_file" or die "$0: open of $output_file failed, error: $! \n";

print OUTPUT ("**********************************************************************\n");
while ( defined ($_=<INPUT>) )
{   

    my $line = $_;
    my ( $ne, $cc_type, $cc_count) = split ('\t',$line);
    my $count=trim($cc_count);
    print("$ne\n");
    while ( defined ($_=<INPUT1>) )
    {
        my $line1 = $_;
        my ( undef, undef, $cc_count1) = split ('\t',$line1);
        my $count1=trim($cc_count1);
        #print("$count1\n");
        while ( defined ($_=<INPUT2>) )
        {
           my $line2 = $_;
           my ( undef, undef, $cc_count2) = split ('\t',$line2);
           my $count2=trim($cc_count2);
           #print("$cc_count2\n");
           while ( defined ($_=<INPUT3>) )
            {
                my $line3 = $_;
                my ( undef, undef, $cc_count3) = split ('\t',$line3);
                my $count3=trim($cc_count3);
                #print("$cc_count3\n");
                while ( defined ($_=<INPUT4>) )
                {
                     my $line4 = $_;
                     my ( undef, undef, $cc_count4) = split ('\t',$line4);
                     my $count4=trim($cc_count4);
                    # print("$cc_count4\n");
                     while ( defined ($_=<INPUT5>) )
                     {
                        my $line5 = $_;
                        my ( undef, undef, $cc_count5) = split ('\t',$line5);
                        my $count5=trim($cc_count5);
                        #print("$cc_count5\n");
                        while ( defined ($_=<INPUT6>) )
                        {
                            my $line6 = $_;
                            my ( undef, undef, $cc_count6) = split ('\t',$line6);
                            my $count6=trim($cc_count6);
                            #print("$cc_count6\n");
                            while ( defined ($_=<INPUT7>) )
                            {
                                my $line7 = $_;
                                my ( undef, undef, $cc_count7) = split ('\t',$line7);
                                my $count7=trim($cc_count7);
                                #print("$cc_count7\n");
                                while ( defined ($_=<INPUT8>) )
                                {
                                    my $line8 = $_;
                                    my ( undef, undef, $cc_count8) = split ('\t',$line8);
                                    my $count8=trim($cc_count8);
                                    #print("$cc_count8\n");
                                    while ( defined ($_=<INPUT9>) )
                                    {
                                         my $line9 = $_;
                                         my ( undef, undef, $cc_count9) = split ('\t',$line9);
                                         my $count9=trim($cc_count9);
                                         #print("$cc_count9\n");
                                         while ( defined ($_=<INPUT10>) )
                                         {
                                             my $line10 = $_;
                                             my ( undef, undef, $cc_count10) = split ('\t',$line10);
                                             my $count10=trim($cc_count10);
                                             #print("$cc_count10\n");
                                             while ( defined ($_=<INPUT11>) )
                                             {
                                                my $line11 = $_;
                                                my ( undef, undef, $cc_count11) = split ('\t',$line11);
                                                my $count11=trim($cc_count11);
                                                #print("$cc_count11\n");

                                                for( $i=0; $i< scalar @count; $i++ )
                                                {
                                                  $total[$i] = $count[$i] + $count1[$i] + $count2[$i] + $count3[$i] + $count4[$i] + $count5[$i] + $count6[$i] + $count7[$i] + $count8[$i] + $count9[$i] + $count10[$i] + $count11[$i];
                                                #   print("@total\n");
                                                }
                                                 print OUTPUT ("$date1 $hour $ne $cc_type   $count  $count1 $count2 $count3 $count4 $count5 $count6 $count7 $count8 $count9 $count10    $count11 $total\n");   
                                               #   print("@total\n");


                                             }
                                          }
                                    }
                                 }
                               }
                        }
                    }
                }
            }
        }
    }           

}

close OUTPUT;
close INPUT;
close INPUT1;
close INPUT2;
close INPUT3;
close INPUT4;
close INPUT5;
close INPUT6;
close INPUT7;
close INPUT8;
close INPUT9;
close INPUT10;
close INPUT11;

I am a newbie in perl. Can you please help me to write this code more logically. For example how can ı read multiple input files without using a lot of while loop and writing into only one output file. Right now, output file shows only first row as true, and the remaining rows just the iteration of the first one, so it is not true. The second problem is,I dont know how to add number values in one row properly. For example I want to add 2 to 18 ( 12 values) and write this value as a final column in output file. Thanks in advance.

evenstar
  • 3
  • 4
  • Use `use strict; use warnings;` in your code. Do you want to add all digits found in any columns separated by **space** for each row? – AbhiNickz May 03 '17 at 15:18
  • 3
    [When you find yourself adding an integer suffix to variable names, think "I should have used an array."](https://stackoverflow.com/a/1829927/100754) – Sinan Ünür May 03 '17 at 15:19
  • I count 17 columns, or are they tab-separated? – ikegami May 03 '17 at 15:37
  • yes they are tab separated, and ı didnt add all of the codes just added the codes about the addition part. – evenstar May 03 '17 at 15:44
  • You need to include `@username` for the person to get notified (unless the comment is in response to their Q or their A.) I've adjusted my answer to split on tabs. – ikegami May 03 '17 at 18:08
  • Ok, that massively changes the question. Most important point - how do the numbers in your input map to your output. They don't appear connected. – Sobrique May 04 '17 at 06:12
  • In the inputs, is if key, column ID, value? – Sobrique May 04 '17 at 06:19
  • hi Sobrique, in every input file column ID 3 ( when considered tab separated) is the value that I want to show in the output file and also want to add. – evenstar May 04 '17 at 16:01

4 Answers4

4

OK, any point you start numbering variables, you should be seriously thinking about using an array instead.

And that goes if they're arrays too. So you might be able to use an array of arrays, but it's unclear quite what you're actually putting into $count.

But for your problem, I'd tackle it like this:

#!/usr/bin/env perl

use strict;
use warnings;


#iterate the DATA filehandle below, line by line. 
while ( <DATA> ) {
    #split the row on whitespace. 
    my @row = split; 
    my $sum;
    #iterate each field
    foreach my $value ( @row ) {  
        #increment the sum by the value, if it's numeric. 
        if ( $value =~ m/^\d+$/ ) { 
           $sum += $value; 
        }
    }
    #print the sum for this row. 
    print $sum,"\n";
}


__DATA__
2017-02-03 0 ACME A 0   2   4   43  4   4   25  4   3   26  4   4   18

And that way, you don't actually need an array of arrays at all.

Note - you can scale this up to your input, probably by just using <> as your input file handle, which reads files specified on command line or STDIN rather than the __DATA__ filehandle.

Sobrique
  • 52,974
  • 7
  • 60
  • 101
  • It looks like you need to `chomp; my @row = split /\t/;` as one of the fields contains whitespace. See the comments on the question. – Borodin May 03 '17 at 23:48
  • And I would `use List::Util 'sum'` and `my $sum = sum map { /^\d+$/ ? $_ : 0 } @row` – Borodin May 03 '17 at 23:51
  • Without chomp, it still works, as the linefeed numifies correctly. – Sobrique May 04 '17 at 06:09
  • Sure, but I don't like doing that in case the values are ever used for something else. In particular `"0"` is *false* while `"0\n"` is *true*. – Borodin May 04 '17 at 10:07
2
sub sum { my $sum; $sum += $_ for @_; $sum }

my $sum = sum
   @count,
   @count1,
   ...
   @count10,
   @count11;

Rather than having a ton of arrays, you should probably have an array of arrays (or hash of arrays).

sub sum { my $sum; $sum += $_ for @_; $sum }

while (<>) {
    chomp;
    my @fields = split /\t/;
    push @aoa, \@fields;
}

my $sum = sum map { @$_[4..15] } @aoa;

or just

my $sum;
while (<>) {
    chomp;
    my @fields = split /\t/;
    $sum += $_ for @fields[4..15];
}

(There appears to be 17 columns, yet you say there are 16, so I'm assuming the whitespace beteween ACME A isn't a tab. Adjust the indexes as needed.)

ikegami
  • 367,544
  • 15
  • 269
  • 518
2

The script below will sum all numeric columns in the data individually and put the sums in an hash called %counts. The keys of the hash will be variable names (which I would normally infer from the header of the file, but you do not provide it, so I made them up).

#!/usr/bin/env perl

use strict;
use warnings;

use List::Util qw( sum );

my %counts;

while (my $line = <DATA>) {
    my (@cols) = split ' ', $line;
    my @numeric = map [$_, $cols[$_]], grep $cols[$_] =~ /^[0-9]+\z/, 0 .. $#cols;
    for my $entry ( @numeric ) {
        $counts{ 'VAR' . $entry->[0] } += $entry->[1];
    }
}

use Data::Dumper;
print Dumper \%counts;

printf "Grand total = %d\n", sum values %counts;

__DATA__
2017-02-03 0 ACME A 0   2   4   43  4   4   25  4   3   26  4   4   18
2017-02-03 0 ACME A 0   2   4   43  4   4   25  4   3   26  4   4   18
2017-02-03 0 ACME A 0   2   4   43  4   4   25  4   3   26  4   4   18
2017-02-03 0 ACME A 0   2   4   43  4   4   25  4   3   26  4   4   18
2017-02-03 0 ACME A 0   2   4   43  4   4   25  4   3   26  4   4   18

Output:

$ perl s.pl                                     
$VAR1 = {                                       
          'VAR7' => 215,                        
          'VAR15' => 20,                        
          'VAR8' => 20,                         
          'VAR11' => 20,                        
          'VAR14' => 20,                        
          'VAR10' => 125,                       
          'VAR12' => 15,                        
          'VAR1' => 0,                          
          'VAR4' => 0,                          
          'VAR5' => 10,                         
          'VAR6' => 20,                         
          'VAR9' => 20,                         
          'VAR16' => 90,                        
          'VAR13' => 130                        
        };                                      
Grand total = 705                               
Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339
1

This solution reads the input file and splits each line, storing the result as an array of arrays. A pair of map calls reduces that data to an array of column totals

There is clearly an issue with some of the data not being numeric, so each column is tested to see if it contains any non-numeric values, in which case undef is provided as the total

I have used first from List::Util even though all would be clearer because it is only more recent versions of the module that provide the latter

I have tested this by creating a file with two copies of your line of data. (Please provide a more comprehensive data sample in the future.)

The program expects the path to the input file as a parameter on the command line

I have used Data::Dumper only to reveal the result of the calculation

use strict;
use warnings 'all';

use List::Util   qw/ first sum /;
use Scalar::Util qw/ looks_like_number /;

our @ARGV = 'data.txt';

my @data = map [ split ], <>;

my @totals = map {
    my $i = $_;
    my @column = map { $_->[$i] }  @data;
    defined( first { not looks_like_number($_) } @column) ? undef : sum(@column);
} 0.. $#{$data[0]};

use Data::Dumper;
print Dumper \@totals;

If you are using a more recent copy of List::Util that provided all, then you can make use of it by changing the use statement to

use List::Util qw/ all sum /;

and rewriting the defined( ... ) line to

all { looks_like_number($_) } @column ? sum(@column) : undef;

output

$VAR1 = [
          undef,
          '0',
          undef,
          undef,
          '0',
          '4',
          '8',
          '86',
          '8',
          '8',
          '50',
          '8',
          '6',
          '52',
          '8',
          '8',
          '36'
        ];
Borodin
  • 126,100
  • 9
  • 70
  • 144