Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Smart way to read a file vertically?

by Anonymous Monk
on Jun 05, 2012 at 21:10 UTC ( #974564=perlquestion: print w/ replies, xml ) Need Help??
Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks!
I am looking to see if there could be a clever way to read a tab-separated file (copied from an excel sheet) vertically.
Image that you have:
NAME LAST_NAME PHONE EMAIL John Smith 1234 lala@lala.com Peter Jones 6789 ttt@yahoo.com George Lukas 9086 lll@hotmail.com
and you want to print out firstly the list of names, then the list of last names, the list of phones and the list of emails.
My approach (maybe a stupid one) would be to read the first line, split it using "\t" as delimeter, and then, while reading each line, splitting them as well and appending, for example, the preffix NAME to each element of each line that appears in the [0] position of the temporary array that will be created.
Can you show me another, more efficient way for this?

Comment on Smart way to read a file vertically?
Download Code
Re: Smart way to read a file vertically?
by thomas895 (Hermit) on Jun 05, 2012 at 21:17 UTC

    See DBD::CSV from the DBI database drivers.
    Or, if you want to do it yourself, use Txt::CSV_XS or something similar.

    Yes, you can do this yourself, but why bother? Someone else has already done that, hence those modules. Or, if you want to use the Excel speadsheets directly, try the Spreadsheet::XLSX, for example.

    ~Thomas~
    confess( "I offer no guarantees on my code." );
Re: Smart way to read a file vertically?
by toolic (Chancellor) on Jun 05, 2012 at 21:21 UTC
    use warnings; use strict; my %data; while (<DATA>) { my @cols = split; push @{ $data{first} }, $cols[0]; push @{ $data{last } }, $cols[1]; push @{ $data{phone} }, $cols[2]; push @{ $data{email} }, $cols[3]; } for my $item (qw(first last phone email)) { print "$item\n"; print "$_\n" for @{ $data{$item} }; print "\n"; } __DATA__ John Smith 1234 lala@lala.com Peter Jones 6789 ttt@yahoo.com George Lukas 9086 lll@hotmail.com

    prints out:

    first John Peter George last Smith Jones Lukas phone 1234 6789 9086 email lala@lala.com ttt@yahoo.com lll@hotmail.com

      This fails for 'Mary Lou Retton' and 'Ludwig van Beethoven'.

Re: Smart way to read a file vertically?
by snape (Pilgrim) on Jun 05, 2012 at 21:22 UTC

    Your method is perfect if you are interested in reading particular column or columns of the file. Also, genrally in all programming languages we read the file row by row and not column by column

    I can suggest a lame method but that is way to complex. If you are interested in reading the file vertically taking account of all the columns then you could transpose the file and then read it. Something like this:

    for my $row (@rows) { for my $column (0 .. $#{$row}) { push(@{$transposed[$column]}, $row->[$column]); } } for my $new_row (@transposed) { for my $new_col (@{$new_row}) { print $new_col, " "; } print "\n"; }

    Again it is a lame method.

      Thanks guys to all of you that put an effort into helping me... I think I'll try out the 2 snipets of code, but also check out the modules as suggested!
      Thanks for always being here to help the newbies!
Re: Smart way to read a file vertically?
by sundialsvc4 (Monsignor) on Jun 06, 2012 at 01:42 UTC

    Glad you found your answer.   In passing, I would note that the problem as you described it could also reasonably be approached by ... ummmm ... simply reading the file four times in a row!   (Close it and reopen it each time, why not, or rewind it...)   Given the way that operating systems rather routinely cache file information when given a chance, performance of this approach might well be excellent.   And, this approach would of course work for an arbitrary amount of data, e.g. far in excess of available memory-size.

Re: Smart way to read a file vertically?
by kcott (Abbot) on Jun 06, 2012 at 08:58 UTC

    Here's a generic technique to achieve what you want based on your supplied data.

    #!/usr/bin/env perl use strict; use warnings; my @labels; my %col_data; while (<DATA>) { chomp; my @cells = split /\t/; if ($. == 1) { @labels = @cells; } else { push @{$col_data{$labels[$_]}} => $cells[$_] for (0 .. $#label +s); } } print join(qq{\n} => $_, @{$col_data{$_}}), qq{\n\n} for @labels; __DATA__ NAME LAST_NAME PHONE EMAIL John Smith 1234 lala@lala.com Peter Jones 6789 ttt@yahoo.com George Lukas 9086 lll@hotmail.com

    Here's the output:

    $ pm_read_vert.pl NAME John Peter George LAST_NAME Smith Jones Lukas PHONE 1234 6789 9086 EMAIL lala@lala.com ttt@yahoo.com lll@hotmail.com

    -- Ken

Re: Smart way to read a file vertically?
by johngg (Abbot) on Jun 06, 2012 at 10:13 UTC

    Similar to other solutions but using push with a ternary and maps.

    use strict; use warnings; use 5.010; open my $inFH, q{<}, \ <<'EOD' or die qq{open: < HEREDOC: $!\n}; NAME LAST_NAME PHONE EMAIL John Smith 1234 lala@lala.com Peter Jones 6789 ttt@yahoo.com George Lukas 9086 lll@hotmail.com EOD my( @N, @LN, @P, @E ); push @{ $_->[ 0 ] == 1 ? \ @N : $_->[ 0 ] == 2 ? \ @LN : $_->[ 0 ] == 3 ? \ @P : \ @E }, $_->[ 1 ] for map { chomp; my $col = 0; map { [ ++ $col, $_ ] } split m{\t}; } <$inFH>; close $inFH or die qq{close: < HEREDOC: $!\n}; say for @N, q{}, @LN, q{}, @P, q{}, @E;

    The output.

    NAME John Peter George LAST_NAME Smith Jones Lukas PHONE 1234 6789 9086 EMAIL lala@lala.com ttt@yahoo.com lll@hotmail.com

    I hope this is of interest.

    Update: As pointed out by Not_a_Number, the code would have failed for some names. I had forgotten to put tabs back into the data after the copy'n'paste put in the displayed spaces :-(

    Code now corrected.

    Cheers,

    JohnGG

      Fails for 'Mary Lou Retton' and 'Ludwig van Beethoven'

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://974564]
Approved by toolic
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others lurking in the Monastery: (7)
As of 2014-07-29 15:58 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My favorite superfluous repetitious redundant duplicative phrase is:









    Results (220 votes), past polls