thanos1983 has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks,

This is my second question for today, so my apologies for that but no matter what I tried I was not able to find the solution that I was looking for.

I have created a script that takes *.text file(s) as argument input(s) and process them. So far the script works fine but I can not get the desired output.

I want to have the content of the files printed in concatenation based on line by line of each file.

Update on the output.

Sample of desired output printout:

1 Line_1_3 Line_3_3 Line_4_3 2 Line_2_3 (empty) Line_5_3 3 (empty) (empty) Line_6_3 4 (empty) (empty) Line_7_3 . . . . . . . . . . . . n Line_n_3 Line_n_3 Line_n_3[n]

Text file sample of sample.txt:

Line_1:Line_1_1:Line_1_2:Line_1_3:Line_1_4 Line_2:Line_2_1:Line_2_2:Line_2_3:Line_2_4

Text file sample of sample_2.txt:

Line_3:Line_3_1:Line_3_2:Line_3_3:Line_3_4

Text file sample of sample_3.txt:

Line_4:Line_4_1:Line_4_2:Line_4_3:Line_4_4 Line_5:Line_5_1:Line_5_2:Line_6_3:Line_5_4 Line_6:Line_6_1:Line_6_2:Line_6_3:Line_6_4 Line_7:Line_7_1:Line_7_2:Line_7_3:Line_7_4

Each file contains data, I import the data on arrays then I short them on array of arrays. I thought that by inserting them into an array by separate arrays, will be much easier for shorting after. But due to lack of experience with array of arrays I manage to find my self in a deadened.

Final update with Solution.

First of all I want to say thank you to Cristoforo for his assistance and he helped to find the solution to my problem.

Working code of array of arrays:

#!/usr/bin/perl use strict; use warnings; use Text::Table; use Data::Dumper; use List::Util qw{max}; use Fcntl qw(:flock); # import LOCK_* and SEEK_END constants $| = 1; my (@result , @values , @array); sub array_sub { foreach my $arg (@_) { open (READ, "<" , $arg) or die ("Could not open: ".$arg." - $!\n"); flock(READ, LOCK_EX) or die "Could not lock '".$arg."' - $!\n"; if (-z "".$arg."") { print "File '".$arg."' is empty!\n"; # -z File has zero size (is empty). } my @doc_read = <READ>; chomp @doc_read; foreach $_ (@doc_read) { @result = split (':', $_); if (/^\s*$/) { # /^\s*$/ check for "blank" lines may contain s +paces or tabs next; } push @values, $result[3]; # get timestamp } # push an array to another to create 2-dimentional array push (@array, [@values]); @values = (); close (READ) or die ("Could not close: ".$arg." - $!\n"); } my $max_idx = max map $#$_, @array; =table structure If no columns are specified, the number of columns is taken from t +he first line of data added to the table. The effect is as if you had speci +fied Text::Table->new( ( '') x $n), where $n is the number of columns. =cut my $tb = Text::Table->new; =loop values $i = maximum number or array values $_ = maximym number of characters =cut foreach my $i (0 .. $max_idx) { $tb->add( map $array[$_][$i], 0 .. $#array); } return $tb; } my $a_table = array_sub(@ARGV); print $a_table;

Sample of output:

$VAR1 = [ [ 'Line_1_3', 'Line_2_3' ], [ 'Line_3_3' ], [ 'Line_4_3', 'Line_5_3', 'Line_6_3', 'Line_7_3' ] ]; Line_1_3 Line_3_3 Line_4_3 Line_2_3 Line_5_3 Line_6_3 Line_7_3

Working code of array of hashes:

#!/usr/bin/perl use strict; use warnings; use Text::Table; use Data::Dumper; use List::Util qw{max}; use Fcntl qw(:flock); # import LOCK_* and SEEK_END constants $| = 1; my $value = (); #create anonymous string_ref my %hash = (); sub hash_sub { foreach my $arg (@_) { open (READ, "<" , $arg) or die ("Could not open: ".$arg." - $!\n"); flock(READ, LOCK_EX) or die "Could not lock '".$arg."' - $!\n"; if (-z "".$arg."") { print "File '".$arg."' is empty!\n"; # -z File has zero size (is empty). } my @doc_read = <READ>; chomp @doc_read; foreach $_ (@doc_read) { my @result = split (':', $_); if (/^\s*$/) { # /^\s*$/ check for "blank" lines may contain s +paces or tabs next; } push (@$value , $result[3]); } $hash{$arg} = $value; $value = (); # emptying the string_ref for the next ARGV close (READ) or die ("Could not close: ".$arg." - $!\n"); } my $max_idx = max map $#$_, values %hash; my $tb = Text::Table->new; for my $i (0 .. $max_idx) { $tb->add( map $hash{$_}[$i], sort keys %hash); } return $tb; } my $h_table = hash_sub(@ARGV); print $h_table;

Sample of output:

$VAR1 = { 'sample.txt' => [ 'Line_1_3', 'Line_2_3' ], 'sample_2.txt' => [ 'Line_3_3' ], 'sample_3.txt' => [ 'Line_4_3', 'Line_5_3', 'Line_6_3', 'Line_7_3' ] }; Line_1_3 Line_3_3 Line_4_3 Line_2_3 Line_5_3 Line_6_3 Line_7_3

Maybe is extremely easy but I can not find a way to do it. I was reading the ARRAYS OF ARRAYS and the ARRAYS OF HASHES but no matter how many different approaches I tried I did not manage to get the desired output.

Any help is much appreciated.

Thank you all for your time and effort answering my question.

Seeking for Perl wisdom...on the process...not there...yet!

Replies are listed 'Best First'.
Re: How to concatenate a generic array of arrays and an array of hashes
by Cristoforo (Curate) on Jul 06, 2014 at 02:53 UTC
    Borrowing hexcoder's suggestion here, the following code will get want you want (if I understand the problem correctly).
    #!/usr/bin/perl use strict; use warnings; my @value; my $col_count = 0; while (<>) { # read from @ARGV (sample.txt sample_2.txt sample_3.txt) chomp; my (undef, @data) = split /:/; my $row_count = 0; for my $info (@data) { $value[$row_count++][$col_count] = $info; } ++$col_count; } for my $v (@value) { print join(" ", @$v), "\n"; }
    Using your 3 sample files, this prints:
    Line_1_1 Line_2_1 Line_3_1 Line_4_1 Line_5_1 Line_6_1 Line_7_1 Line_1_2 Line_2_2 Line_3_2 Line_4_2 Line_5_2 Line_6_2 Line_7_2 Line_1_3 Line_2_3 Line_3_3 Line_4_3 Line_6_3 Line_6_3 Line_7_3 Line_1_4 Line_2_4 Line_3_4 Line_4_4 Line_5_4 Line_6_4 Line_7_4
    Chris

      Hello Christoforo,

      Thanks for your time and effort to reply to my question. Well unfortunately this is not exactly what I want to do. My current solution is exactly what I want.

      Sample of output using 2 dimension arrays:

      $VAR1 = [ [ 'Line_1_3', 'Line_2_3' ], [ 'Line_3_3' ], [ 'Line_4_3', 'Line_5_3', 'Line_6_3', 'Line_7_3' ] ];

      Sample of array with hashes:

      $VAR1 = { 'sample.txt' => [ 'Line_1_3', 'Line_2_3' ], 'sample_2.txt' => [ 'Line_3_3' ], 'sample_3.txt' => [ 'Line_4_3', 'Line_5_3', 'Line_6_3', 'Line_7_3' ] };

      The reason is that possibly the files are not the same in line (size) etc. etc. I am trying to retrieve the arrays one by one so I can play around with it.

      I have found a way to print all data and also to print individual 1 by one the elements but not the arrays. I have an idea in my mind on how to solve it. I did not had the time to work on it, that is the reason that I have not updated my solution.

      But thanks again for your time and effort and sorry if my sketch is not so clear.

      Seeking for Perl wisdom...on the process...not there...yet!
        Each file contains data, I import the data on arrays then I short them on array of arrays
        I don't know what exactly you wish to do - do you mean sort?

        If you want to sort them, how would your output appear?

        You stated your solution is what you want.

        I have found a way to print all data and also to print individual 1 by one the elements but not the arrays.
        I don't know what you mean in the statement above. How do you want to print the arrays?
Re: How to concatenate a generic array of arrays and an array of hashes
by boftx (Deacon) on Jul 06, 2014 at 23:41 UTC

    I suspect that what you are looking for is an array of hashes.

    $VAR1 = [ { sample.txt => [ 'Line_1_3', 'Line_2_3' ] }, ];
    I find it usually helps to consume some Scotch before diving into nested data structures. It might not make the answer easier to see, but at least I don't mind the time it takes so much.

    You must always remember that the primary goal is to drain the swamp even when you are hip-deep in alligators.

      Hello boftx,

      Well up to this point I got it, the problem is after. I am trying to print them in columns based on each array separately with spaces in between and simultaneously in case that the files have different sizes.

      Ok this sounds really complicated so I will try to draw it, based on the sample files that I have posted here.

      Line_1_3 Line_3_3 Line_4_3 Line_2_3 Line_5_3 Line_6_3 Line_7_3

      This is the expected printed format. Well I am trying to get access to each array elements individually after reading them from the argument input, because I want to apply mathematical calculation on array[0] and array3 for example. It dose not matter if they have same number or lines but it does matter when it comes to printing on the screen or in a file.txt etc.

      This is the reason that initially solve it with 2 dimension arrays and then with array and hashes. In order to get the best possible output out of them.

      Apologies if my description it is really confusing so far.

      Again thanks for your time and effort to assist me with my problem.

      Seeking for Perl wisdom...on the process...not there...yet!

        OK, here's some code that does what you want. I've not included the part that reads the data.

        #!/usr/bin/perl use warnings; use strict; use List::Util qw/max/; my $VAR1 = { 'sample.txt' => [ 'Line_1_3long', 'Line_2_3' ], 'sample_2.txt' => [ 'Line_3_3longer' ], 'sample_3.txt' => [ 'Line_4_3', 'Line_5_3', 'Line_6_3evenlonger', 'Line_7_3', ] }; my %maxlength = (); foreach my $key (sort keys %$VAR1) { $maxlength{$key} = max map { length } @{$VAR1->{$key}}; } my $maxelements = max map { $#$_ } values %$VAR1; foreach my $line (0..$maxelements) { foreach my $key (sort keys %$VAR1) { if($line >= @{$VAR1->{$key}}) { print " " x ($maxlength{$key} + 1); } else { print $VAR1->{$key}->[$line]; print " " x ($maxlength{$key} - length($VAR1->{$key}->[$line]) + + 1); } } print "\n"; }

        This prints:

        $ perl test.pl Line_1_3long Line_3_3longer Line_4_3 Line_2_3 Line_5_3 Line_6_3evenlonger Line_7_3 $

        Notes:

        1. If you know your pieces of data are always going to be the same length, you can leave out the %maxlength computation, and replace $maxlength{$key} by this known value.
        2. You might be able to use formats (see perlform), but I have literally zero experience with them and couldn't say.

        I hope this helps. My bill for an hour (rounded up) of paid consultant work's in the mail. :)

Re: How to concatenate a generic array of arrays and an array of hashes
by Anonymous Monk on Jul 06, 2014 at 13:21 UTC
    You know, it's pretty hard to understand what you want to accomplish... but I got an impression that you want to interleave your arrays somehow. You probably should use C-style 'for' loop for that.
    my $array_size = @array; # scalar assignement yields the size (number +of elements) of @array for (my $i = 0; $i < $array_size; $i++) { print $array[ $i ][0], $array[ $i ][1], $array[ $i ][2]; # etc }

      Hello Anonymous Monk,

      You are absolutely right it is difficult to describe what I am trying to accomplish. I had in my mind your solution and I have actually tried it on a previous attempt to solve my problem but not successfully so far.

      Well I am trying to become familiar with 2 dimension arrays and hashes so I can manipulate the data in them by any possible way. This is my goal right now. Unfortunately this is the first time that I am using 2 dimension arrays and with hashes at the same time, so it takes a bit more time to understand how to use them.

      I have something in my mind if it works I will post my answer in case that I might assist someone on the future.

      Again I want to say thank you for your time and effort to assist me with my question.

      Seeking for Perl wisdom...on the process...not there...yet!