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

This seemed easy to me last night and for some reason I can't get this to work on my head, or in script.

I have a log file that looks like

Big Bird 10 20 40 50 Calvin Klein 45 30 100 80 10 Mother Natures 100 100 23
I need to open this log file, sort my last name alphabetically, and print everything out. Easy? I knew it was but my mind is playing tricks on me.

My original thought was to split it by spaces at first so I can get the two names, and all the numbers in one var since they're not important to have separate. Then create a new array to store the new results in an order I can sort. From there, just print it out.

The problem I am running into is the digits, I can't capture all of them no matter what I've tried.

Can someone help me find a solution and let me know why my solutions weren't working?

open (LOG, $log) or die "Error: $!"; my @lines = <LOG>; close(LOG) or die "Error: $!"; my @good_results; foreach my $key (@lines) { # my ($fname, $lname, $grades) = split(/\w+/, $key); my ($fname, $lname) = split(/ /, $key); $key =~ m/\w+\s+(\d+\s)$/; my $grades = $1; print "$lname and $fname $grades\n"; #push(@good_results, "$lname $fname $grades"); } #print join("\n", sort @good_results);

Replies are listed 'Best First'.
Re: reading a log file and sorting by last name
by Limbic~Region (Chancellor) on Oct 09, 2006 at 15:46 UTC
    Anonymous Monk,
    Updated to reflect your updated requirements:
    You havent said how big your file is but let us assume you have enough resources to store the whole file in memory.
    my $log_file = $ARGV[0] || 'log.file'; open(my $fh, '<', $log_file) or die "Unable to open '$log_file' for re +ading: $!"; my %name; while (<$fh>) { chomp; my ($fn, $ln, $rest) = $_ =~ /^(\w+)\s+(\w+)(.*)/; $name{$ln} = "$ln $fn$rest\n"; } for (sort keys %name) { print "$name{$_}"; }
    It does assume last names are unique. If this is not the case, you could always use a two level hash $name{$ln}{$fn} and if that still is not unique you could use $rest as in $name{$ln}{$fn}{$rest}.

    Cheers - L~R

Re: reading a log file and sorting by last name
by jdporter (Paladin) on Oct 09, 2006 at 15:55 UTC
    my( $fname, $lname, $grades ) = /^(.*?) (\S*?) ([ 0-9]*)$/;

    But I'd probably store the data as an array of arrays, rather than re-joining the string before the sort. I.e.:

    for ( sort { $a->[1] cmp $b->[1] or $a->[0] cmp $b->[0] } map { [ /^(.*?) (\S*?) ([ 0-9]*)$/ ] } @lines ) { print "@$_\n"; }
    We're building the house of the future together.
      my( $fname, $lname, $grades ) = /^(.*?) (\S*?) ([ 0-9]*)$/;

      Also:

      my ($fname, $lname, $grades) = split /\s+/, $_, 3;

      --
      David Serrano

Re: reading a log file and sorting by last name
by Anonymous Monk on Oct 09, 2006 at 15:42 UTC
    Sorry, I forgot to show an example of the print out expected.
    Bird Big 10 20 40 50 Klein Calvin 45 30 100 80 10 Nature Mother 100 100 23
    I guess my example wasn't that good since apparently it was already alphabetized, but you get the idea. There can be any number of numbers at the end in which do NOT need to be sorted.

    Also, in the first commented out split attempt, it was originally \s+\ instead of \w+\.

      If you just want to swap the first and second fields then:
      open (LOG, $log) or die "Error: $!"; print sort map { s/(\S+)(\s+)(\S+)/$3$2$1/; $_ } <LOG>;