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
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} | [reply] [d/l] |
Re: Working With Arrays and Files
by broquaint (Abbot) on Jul 23, 2002 at 19:38 UTC
|
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 | [reply] [d/l] |
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
| [reply] [d/l] [select] |
|
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
| [reply] |
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; | [reply] [d/l] |
|
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....
| [reply] [d/l] |
|
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. | [reply] [d/l] [select] |
|
|
|
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 | [reply] |
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."
| [reply] [d/l] |
|
|