Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

Smart way to read a file vertically?

by Anonymous Monk
on Jun 05, 2012 at 21:10 UTC ( [id://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?

Replies are listed 'Best First'.
Re: Smart way to read a file vertically?
by thomas895 (Deacon) 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 (Bishop) 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 kcott (Archbishop) 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 (Canon) 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'

        If we consider a slightly different situation: Say the first names are in one file, last names in another, and so on. How might one be able to read in from those files and print out to a master list with each column of data side by side? I could read it in and print each file line by line, but I want to print them column by column and don't really know how to do that.
A reply falls below the community's threshold of quality. You may see it by logging in.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
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?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (3)
As of 2024-03-19 11:12 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found