Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

Working With Arrays and Files

by kevinw (Novice)
on Jul 23, 2002 at 19:21 UTC ( [id://184540]=perlquestion: print w/replies, xml ) Need Help??

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

Hello, I was hoping some of you could help me with this problem. I have a file temp in this format:
name1 1 2 3 4 typex name2 3 4 5 6 typey name3 2 3 3 1 typex
and i want to have it printed into file "outfile" in the following way:
typex name1 1 2 3 4 name3 2 3 3 1 typey name2 3 4 5 6
i'm putting the file "temp" into an array in the following way:
while (my $line = <TEMP>) { chomp($line); push @array, $line; my ($name, $column2, $column3, $column4, $column5, $type) = split/ +\s+/; }
but i'm stuck after this...any help would be appreciated since this is my first perl program...thanks in advance

Replies are listed 'Best First'.
Re: Working With Arrays and Files
by thelenm (Vicar) on Jul 23, 2002 at 19:35 UTC
    You've got a good start! What you'll probably want to do is create a hash with the 6th column as keys and the other columns as values. It might end up being a Hash of Arrays of Arrays, like this:
    my %hash; while (my $line = <TEMP>) { chomp($line); my @columns = split ' ', $line; # Add an array of the first four columns to the hash # entry for this type (the type is $columns[5]). Each # hash entry is itself an array of these arrays. push @{$hash{$columns[5]}}, [ @columns[0..4] ]; } # Go through the type names in order, printing out all the # data that was seen with each type foreach my $type (sort keys %hash) { print "$type\n"; foreach my $line (@{$hash{$type}}) { print "@$line\n"; } }
    That may seem pretty complicated if it's your first Perl program. In order to understand exactly what's going on, try reading perlref and perldata to understand more about complicated data structures.

    -- Mike

    --
    just,my${.02}

Re: Working With Arrays and Files
by broquaint (Abbot) on Jul 23, 2002 at 19:38 UTC
    Try this
    my %info; while(<TEMP>) { chomp; my($data, $name) = m< (.*) \s+ (\w+) $ >x; push @{ $info{$name} }, $data; } open(OUT, '>', "outfile") or die("ack - $!"); foreach my $k (sort keys %info) { print OUT $k, "\n"; print OUT $_, "\n" for @{ $info{$k} }; print OUT "\n"; }
    Data structures are your friend (see. perldata for more info on data structures in perl).
    HTH

    _________
    broquaint

Re: Working With Arrays and Files
by fsn (Friar) on Jul 23, 2002 at 19:46 UTC
    The simplest way to do this (atleast for me) is with a hash. Now, the solution is a bit simplistic and it if you need to treat the data in any way before you print it it might not suffice, but it does give you the requested result.
    I know I'm gonna be whacked on the head for not finding a better way of splitting the data.

    #!/usr/bin/perl my %hash; while (<DATA>) { chomp; my ($name, $column2, $column3, $column4, $column5, $type) = sp +lit/\s+/; $hash{$type} = $hash{$type} . "$name $column2 $column3 $column +4 $column5\n"; } foreach $key (sort keys %hash) { print "$key\n$hash{$key}\n"; } __DATA__ name1 1 2 3 4 typex name2 3 4 5 6 typey name3 2 3 3 1 typex
    which gives you the following output:
    typex name1 1 2 3 4 name3 2 3 3 1 typey name2 3 4 5 6
      thanks fsn, is there anyway to format the data in the print statement such that it comes out in straight columns? i usually just do print "%x %y..." etc, but in this case, i'm not sure how to go about it...thanks again
Re: Working With Arrays and Files
by dpuu (Chaplain) on Jul 23, 2002 at 19:48 UTC
    It looks to me like your problem is to first collect/organise the data you want, then to print it out. I recommend storing your lines in a hash, keyed off the last field on the line. I'll use a hash-of-lists-of-lists:
    my %data = (); # get the data while (<TEMP>) { my @fields = split; # get fields my $key = pop @fields; # remove rightmost my $line = [@fields]; # $line is ref to list of fields push @{$data{$key}}, $line; # add to list of lines, in hash } close TEMP; #now print it: foreach my $key (sort keys %data); { print "$key\n"; my @lines = @{$data{$key}}; # list of lines, from hash foreach my $line (@lines); { my @fields = @$line; # list of fields, from array-ref my $text = join(" ", @fields); print "$text\n"; } print "\n"; }
    Let me know if you can't follow the data-structure stuff. I've tried not to use any shortcuts, but I know it can be confusing at first. --Dave;
      thanks for your help dave..... i'm still a lil unsure what this does
      my $key = pop @fields; #is this the same as chomp? my $line = [@fields]; @$line #could you briefly explain the naming convension here?
      and when i print it out, my columns are of different lengths, is there any way i can format it such that it comes out as straight columns? thanks again for your help....
        OK,

        First, I create the @fields array, using the split function with default args (i.e. splits $_ into fields separated by whitespace).

        Then, I use the pop function to remove (and get) the rightmost element of the fields array. (push and pop manipulate the right hand side; shift and unshift manipulate the left). So after the $key has been popped, @fields is an array of all fields, except the rightmost.

        To push a list onto a list of arrays, I need an array reference. I could have used \@fields; but there are subtle ways that can go wrong when you're new to perl data-structures. So instead, I create a new anonymous array reference (using square brackets).

        Later, when I want convert the array-reference back into an array, I need to use the array dereferencing operator: @{$line}. I appologise for using a standard shorthand here: perl interprets @$line as @{$line}.

        Your last question is how to format you colmns more nicely. The easiest way (might work) is to join the elements of the array using a tab, instead of a space:

        my $text = join("\t", @fields);
        If this doesn't work, then there are many alternatives: you could define a format (see books); or you could write some clever padding functions; or you could store the original input text in the hash-of-lines; or you could get a CPAN module such as Data::ShowTable or Text::FormatTable. Personally, I usually don't bother: if I really need to view something as neat tables, then I use a table viewing application (or output as html). --Dave.
Re: Working With Arrays and Files
by kevinw (Novice) on Jul 23, 2002 at 19:33 UTC
    UPDATE the list goes on, it's not only a list with 3 rows....thought it might clear up some confusion
Re: Working With Arrays and Files
by sauoq (Abbot) on Jul 23, 2002 at 21:12 UTC
    If you just have to do it once. . . perl -lne 'my@a=split;push@{$h{$a[5]}},"@a[0..4]\n"}{$"="";print"$_\n@{$h{$_}}"for sort keys%h' infile > outfile
    -sauoq
    "My two cents aren't worth a dime."
    

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (5)
As of 2024-04-23 15:28 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found