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

Hello Friends!
I have been trying to print out a HoA. When I do so using the typical method of:
for $zz(keys %data) { print OUTPUT "@{ $data{$zz} }" }
I get all of the arrays printed out succesively. Each array is composed of several thousand data strings followed by a \n. From an Excel perspective, it would be the equivalent of 4 columns of several thousand rows (per array). What I am aiming to do is get these arrays printed out in succesive columns, so (again in Excel terms) it would be a total of 4 columns x 5 arrays =20 columns total. Anyway, I know that the best way to do this is to say  print "@a,@b,@c";so that they are all printed simultaniously. Hence, I have fished the keys of the array out (the name of the arrays themselves) using  my $scalar= join( ', ',keys %data); Therin lies my problem however. I have the names of the arrays in a scalar, but like calling a program in a different subdirectory, need to be able to pull out the names and figure out how to print the arrays themselves, rather than the names of the arrays. I hope I have elucidated my goals well. Thanks so much!!!
Bioinformatics

Replies are listed 'Best First'.
Re: Custom printing of an HoA
by blokhead (Monsignor) on Oct 03, 2003 at 18:39 UTC
    I'm having some trouble understanding exactly what you mean, but my best guess is that you want something like this:
    key1 key2 key3 key4 key5 $data{key1}[0] $data{key2}[0] $data{key3}[0] $data{key4}[0] $data{ +key5}[0] $data{key1}[1] $data{key2}[1] $data{key3}[1] $data{key4}[1] $data{ +key5}[1] $data{key1}[2] $data{key2}[2] $data{key3}[2] $data{key4}[2] $data{ +key5}[2] ...
    To do this, you'll need to use map to pull out the appropriate array members for each row:
    my $col_width = 20; my @keys = sort keys %data; my $p_format = join(" " => ("%${col_width}s") x @keys) . "\n"; ## $p_format would be "%20s %20s %20s ... %20s\n", so the columns will ## line up even if the data strings are different sizes printf $p_format, @keys; my $i = 0; LOOP: { ## important part: pull out the ith entry in each array my @ith_data = map { $data{$_}[$i] || "" } @keys; ## you mentioned the data strings end in \n chomp @ith_data; printf $p_format, @ith_data; $i++; ## loop again if any array has elements left for (@keys) { redo LOOP if exists $data{$_}[$i]; } }
    Thank heavens for bare-block flow control ;) If that scares you, the only reason I used it is in case the arrays weren't all the same length. If yours are all the same known sizes, you can replace that goofy block with for my $i (0 .. $size-1).

    I used printf to print things out in aligned columns, but if your data strings are all the same length, you could just as easily use print "@ith_data\n"... although that would start looking weird if some arrays run out of elements early. But if your arrays are all the same size, and your data strings are all the same length, you could get this code down to:

    my @keys = sort keys %data; for my $i ( 0 .. $size-1 ) { my @ith_data = map { $data{$_}[$i] || "" } @keys; chomp @ith_data; print "@ith_data\n"; }

    blokhead

      blokhead,
      You may want to modify your map line:
      my @ith_data = map { defined $data{$_}[$i] ? $data{$_}[$i] : '' } @key +s;
      This way 0 and "0" will not get changed to "".

      Cheers - L~R

      This is exactly what I am looking for!! It is a very different way of doing things compared to the direction I was heading, but works very nicely. Always glad to learn new stuff....Thanks!!!
      Bioinformatics
Re: Custom printing of an HoA
by Limbic~Region (Chancellor) on Oct 03, 2003 at 18:39 UTC
    bioinformatics,
    I am not exactly sure I understand. What I think you are looking for is for each "row" to consist of a single element from a list of arrays. This might be what you wanted. I tested it with dummy data.

    #!/usr/bin/perl -w use strict; use Text::CSV; my %data = ( one => [ qw(a b c d e f g h i j k) ], two => [ qw(1 2 3 4 5 6 7 8) ], three => [ qw(john jacob jingle heimer smitz) ] ); my @keys = sort keys %data; my $max = 0; for ( @keys ) { $max = @{$data{$_}} if @{$data{$_}} > $max; } Excel(\@keys); for my $index ( 0 .. $max ) { my @temp; for my $key ( @keys ) { push @temp, defined $data{$key}->[$index] ? $data{$key}->[$ind +ex] : ''; } Excel(\@temp); } sub Excel { my $array = shift; my $csv = Text::CSV->new; if ( $csv->combine(@{$array}) ) { my $string = $csv->string; print $string, "\n"; } else { my $err = $csv->error_input; print "combine() failed on argument: ", $err, "\n"; } }
    Cheers - L~R

    Update: Added Text::CSV stuff since it sounded like the output is going to Excel.

Re: Custom printing of an HoA
by hardburn (Abbot) on Oct 03, 2003 at 18:45 UTC

    Does it need to be readable by an end user, or is it just for debugging something? If debugging, use Data::Dumper.

    ----
    I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
    -- Schemer

    Note: All code is untested, unless otherwise stated

      I've heard a lot about Data::Dumper, but haven't used it much. The data is to be read in excel format, so using Data::Dumper won't help in this situation. Thanks for the suggestion though!!
      Bioinformatics
Re: Custom printing of an HoA
by BrowserUk (Patriarch) on Oct 03, 2003 at 19:27 UTC

    Where does the 4 columns bit come from?

    If each value is "\n" terminated, I would expect to see a single, very long column output from you code

    Unless each individual element of each array actually contains 4 space or comma delimited fields terminated by a newline?

    A little (abbreviated) sample datam plus a C&P from the resultant file and an example of how you would like that same output formatted would go a long way to clarifying your question.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
    If I understand your problem, I can solve it! Of course, the same can be said for you.