john.tm has asked for the wisdom of the Perl Monks concerning the following question:

Hi monks i have a script that creates an array of strings from a file, I am then trying to run a foreach loop and print the tiltle row and each other row vertically side by side.

What i have prints the title row and all the other rows at once. How do i get it to print foreach row seperatly

#!/usr/bin/perl use strict; use warnings; local $" = "'\n'"; open( STDERR, ">&STDOUT" ); my $xlsx_WSD = ( "C:\\Temp\\data.csv"),, 1; my @csvtemp; open( FILE, "<$xlsx_WSD" ) or die "oops\n"; my %data; my @titles; #heaader row while (<FILE>) { chomp; my @strings=split(/,/); foreach (my $i=0; $i<=$#strings; $i++) { #header titles if ($.==1) { $titles[$i]=$strings[$i]; } else { push @{$data{$titles[$i]}}, $strings[$i]; } } } foreach (@titles){ local $"="\t"; print "$_ \t= @{$data{$_}}\n"; }
input file
Animal keepers M/F YEAR DOB AGE FSM PREM ET ND + AL EAL GIRAFFE JAMES LE M 9 10/12/2007 Y Y N N HIPPOS JACKIE LEAN F 6 11/12/2007 Y N Y Y ZEBRAS JAMES LEHERN M 3 12/12/2007 N N N Y LIONS AMIE CAHORT M 1 13/12/2012 Y Y Y N
desired output
Animal GIRAFFE keepers JAMES LE M/F M YEAR 9 DOB 10/12/2007 AGE FSM Y PREM ET Y ND AL N EAL N Animal HIPPOS keepers JACKIE LEANE M/F F YEAR 6 DOB 11/12/2007 AGE FSM Y PREM ET N ND AL Y EAL Y Animal ZEBRAS keepers JAMES LEHERN M/F M YEAR 3 DOB 12/12/2007 AGE FSM N PREM ET N ND AL N EAL Y Animal LIONS keepers AMIE CAHORT M/F M YEAR 1 DOB 13/12/2007 AGE FSM Y PREM ET N ND AL Y EAL N
  • Comment on script to do a foreach on an array of strings outputting the title row and each string element vertically
  • Select or Download Code

Replies are listed 'Best First'.
Re: script to do a foreach on an array of strings outputting the title row and each string element vertically
by GrandFather (Saint) on Dec 28, 2015 at 21:23 UTC

    First up, you should really use a module for handling your tab separated data. Next, think in terms of read a record and print it. Then you get something like:

    #!/usr/bin/perl use strict; use warnings; use Text::CSV; my $csv = Text::CSV->new({binary => 1, sep_char => "\t"}); my @headers = @{$csv->getline(*DATA)}; while (my @data = @{$csv->getline(*DATA) // []}) { print "$_\t", shift @data, "\n" for @headers; print "\n"; } __DATA__ Animal keepers M/F YEAR DOB AGE FSM PREM ET ND + AL EAL GIRAFFE JAMES LE M 9 10/12/2007 Y Y N N HIPPOS JACKIE LEAN F 6 11/12/2007 Y N Y Y ZEBRAS JAMES LEHERN M 3 12/12/2007 N N N Y LIONS AMIE CAHORT M 1 13/12/2012 Y Y Y N

    Prints:

    Animal GIRAFFE keepers JAMES LE M/F M YEAR 9 DOB 10/12/2007 AGE FSM Y PREM ET Y ND AL N EAL N Animal HIPPOS keepers JACKIE LEAN M/F F YEAR 6 DOB 11/12/2007 AGE FSM Y PREM ET N ND AL Y EAL Y Animal ZEBRAS keepers JAMES LEHERN M/F M YEAR 3 DOB 12/12/2007 AGE FSM N PREM ET N ND AL N EAL Y Animal LIONS keepers AMIE CAHORT M/F M YEAR 1 DOB 13/12/2012 AGE FSM Y PREM ET Y ND AL Y EAL N

    The @{...} stuff turns the array reference returned by Text::CSV::getline() into a list. The // [] bit in the while loop suppresses a warning by turning the end of file undef into an empty array.

    Premature optimization is the root of all job security
      mamma mia! what expressive Perl!

      Thanks for your replies GrandFather
      L*
      There are no rules, there are no thumbs..
      Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: script to do a foreach on an array of strings outputting the title row and each string element vertically
by 1nickt (Canon) on Dec 28, 2015 at 20:41 UTC
    Your input data doesn't match your script: it's not comma-separated. I added commas as separators and transformed the input data to:
    Animal,keepers,M/F,YEAR,DOB,AGE,FSM,PREM ET,ND AL,EAL GIRAFFE,JAMES LE,M,9,10/12/2007,,Y,Y,N,N HIPPOS,JACKIE LEAN,F,6,11/12/2007,,Y,N,Y,Y ZEBRAS,JAMES LEHERN,M,3,12/12/2007,,N,N,N,Y LIONS,AMIE CAHORT,M,1,13/12/2012,,Y,Y,Y,N
    and then this code got your expected output:
    #!/usr/bin/perl use strict; use warnings; use 5.010; my $file = '1151282.dat'; open my $fh, '<', $file or die $!; my @headers; while ( <$fh> ) { chomp; if ( $. == 1 ) { @headers = split ','; next; } my @strings = split ','; for ( 0 .. @headers - 1 ) { say "$headers[ $_ ] $strings[ $_ ]"; } say ''; } __END__
    However, if you really have CSV data, you should use a module to parse it; I recommend Text::CSV_XS

    Hope this helps!

    The way forward always starts with a minimal test.
Re: script to do a foreach on an array of strings outputting the title row and each string element vertically
by Discipulus (Canon) on Dec 28, 2015 at 20:32 UTC
    Hello, you need to normalize somehow your data before elaborating the results: infact you have at least 2 field of two separaated words and at least the value of the name of the keeper with a space (the code below is broken for a keeper named just 'Tarzan' as for one named 'Vladimir Ilyich Ulyanov').
    You can practice splice to modify the fields outside the loop, considering just the first line. In the loop you'll join firstname+lastname to have a singular field for them.
    After this sanitazing work, the game is simple. I leaved some helpfull debugging print statement commented, to see how splice works (i not use it so often...)
    use strict; use warnings; my @fields = split /\s+/, <DATA>; # print "BEFORE: ",(join '|',@fields),"\n"; my $prem_et = $fields[7].' '.$fields[8]; splice @fields,7,2,$prem_et; my $nd_al = $fields[8].' '.$fields[9]; splice @fields,8,2,$nd_al; # print "AFTER: ",(join '|',@fields),"\n"; while (<DATA>){ chomp; my @entries = split /\s+/,$_; # look at @entries before joining the name # print +(join '|',@entries),"\n"; my $name_with_space = $entries[1].' '.$entries[2]; # see the doc for splice: we remove item 1,2 and replace t +he with a single # $name_with_space splice @entries,1,2,$name_with_space; # UPDATE for null age @entries = (@entries[0..4],'',@entries[5..$#entries]); # but since we learn 'splice' we can do with it too: # splice @entries,4,1,$entries[4],''; # look at entries after splice # print +(join '|',@entries),"\n"; # foreach index of entries we print both corresponding fie +ld and entry print map {"$fields[$_]\t$entries[$_]\n" } 0..$#entries; print "\n"; } __DATA__ Animal keepers M/F YEAR DOB AGE FSM PREM ET ND + AL EAL GIRAFFE JAMES LE M 9 10/12/2007 Y Y N N HIPPOS JACKIE LEAN F 6 11/12/2007 Y N Y Y ZEBRAS JAMES LEHERN M 3 12/12/2007 N N N Y LIONS AMIE CAHORT M 1 13/12/2012 Y Y Y N
    with the output:
    Animal GIRAFFE keepers JAMES LE M/F M YEAR 9 DOB 10/12/2007 AGE FSM Y PREM ET Y ND AL N EAL N Animal HIPPOS keepers JACKIE LEAN M/F F YEAR 6 DOB 11/12/2007 AGE FSM Y PREM ET N ND AL Y EAL Y Animal ZEBRAS keepers JAMES LEHERN M/F M YEAR 3 DOB 12/12/2007 AGE FSM N PREM ET N ND AL N EAL Y Animal LIONS keepers AMIE CAHORT M/F M YEAR 1 DOB 13/12/2012 AGE FSM Y PREM ET Y ND AL Y EAL N


    HtH (animals too!)
    L*
    UPDATED: i've not noticed you also have the age value empty! i've corrected the above.
    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: script to do a foreach on an array of strings outputting the title row and each string element vertically
by poj (Abbot) on Dec 28, 2015 at 20:52 UTC

    It looks like you have created a Hash of Arrays (HoA) whereas you really need an Array of Hashes (AoH)

    use strict; use warnings; my @data = (); my @title = split /,/,<DATA>; chomp(@title); while (<DATA>) { chomp; my %rec = (); @rec{@title} = split(/,/); push @data,\%rec; } for my $rec (@data){ print "$_\t$rec->{$_}\n" for @title; print "\n"; } __DATA__ Animal,keepers,M/F,YEAR,DOB,AGE,FSM,PREM ET,ND AL,EAL GIRAFFE,JAMES LE,M,9,10/12/2007,,Y,Y,N,N HIPPOS,JACKIE LEAN,F,6,11/12/2007,,Y,N,Y,Y ZEBRAS,JAMES LEHERN,M,3,12/12/2007,,N,N,N,Y LIONS,AMIE CAHORT,M,1,13/12/2012,,Y,Y,Y,N
    poj