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

I've been going over the perldocs and trying to figure this out for a few weeks now.. I'm rusty, but am trying to make use of map() to convert an array of lines from a log file into a hash of array of arrays keyed by one of the values in the logfile line.

An example format for a logline: 2010-08-10 13:59:54 GGS INFO 260 Something Something Manager for Monitor, mgr.prm: Lag for REPLICATION REP is 00:00:00 (checkpoint updated 00:00:02 ago).

The $key, in this line, would be "260" (without quotes).

The value would be the line itself, but as an array.

There could be many such "values" per $key, so the $key is not unique in this logfile. I thought a hash of arrays would fit the bill because,for each $key, there' be several lines.

An excerpt from my current attempts: my %sorted_msgs = map { $_[5], $_[0] } sort { Date_Cmp($a->[1], $b->[1]) } map { my @logline = split(/\s+/, $_, 5); my $timestring = '\'' . $logline[0] . ' ' . $logline[1] +. '\''; [ $_, ParseDate($timestring), $logline[0], $logline[1], +$logline[2], $logline[3], $logline[4] ]; } @matched_lines;

In the split, after #5, I capture the rest of the logline.

The ParseDate is from Date::Manip, and works flawlessly in other routines, so i hope that doesn't distract from the question.

The first, inner map, is where I transform the array into anther, temporary array of values that I munged and/or want to be able to access. Then I do a sort on the timestamp, and, lastly, I (am trying) to convert values in the transformed array into a hash of arrays.

Dumper shows: DUMPER: $VAR1 = 'HASH(0x82442a0) ';

Replies are listed 'Best First'.
Re: Using map to convert an array into a hash of array of arrays
by moritz (Cardinal) on Aug 10, 2010 at 14:23 UTC
    Does it have to be map?
    my %sorted_msgs; for (@lines) { my $key = obtain key here; my $value = [ value array items here ]; push @{$sorted_msgs{$key}}, $value; }
    Perl 6 - links to (nearly) everything that is Perl 6.
Re: Using map to convert an array into a hash of array of arrays
by roboticus (Chancellor) on Aug 10, 2010 at 14:42 UTC

    rjoost:

    I'm going to agree with moritz. If you're having that much trouble figuring it out, then how will you be able to debug it or modify it three months from now? It's far too easy to make code that's hard to maintain.

    I'd suggest making a subroutine that will chop up the line and return a hash reference, then you can use map to call your subroutine:

    my %sorted_msgs = map { $_[5], $_[0] } sort { Date_Cmp($a->[1], $b->[1]) } map { crunchit($_) } @matched_lines; sub crunchit { ... }

    By the way, since you're calling your hash %sorted_msgs, shouldn't your sort be on $_[5] rather than $_[1], or perhaps your hash key should be $_[1]? Otherwise, you won't actually have a sorted list of messages, would you? (Or are you simply trying to ensure that later entries overlay earlier entries?)

    ...roboticus

      Ok, Roboticus and Moritz, thanks for the tips. I get it now ;-) I'm really getting into the more functional aspects of Perl's map as a transformative helper!

      my %alertlog_mapper = map { $_->[1] => [ $_->[3], $_->[4], $_->[6], $_ +->[2], $_->[5] ] } sort { Date_Cmp($a->[2], $b->[2]) } map { my @logline = (); my ($msg_id, $timestring, $min, $sec, $secs, $secs_before, + $secs_after); @logline = split(/\s+/, $_, 5); $timestring = $logline[0] . ' ' . $logline[1]; $min = substr($logline[1], 3, 2); $sec = substr($logline[1], 6, 2); $secs = $min * 60 + $sec; $secs_before = $secs - 5; $secs_after = $secs +5; #my @lookup_alerts = & $msg_id = $logline[3]; [ $_, $logline[3], ParseDate($timestring), $logline[0], $l +ogline[1], $logline[2], $logline[4] ]; } @gmsgs;

      I'll keep up with the perldocs and keep working on perl data structures, as time permits.

        I'm revisiting to undertand maps more...been reading the perldocs, almost there, but could use some clarification.

        If I've got Dumper output like this:

        $VAR1 = [ '2100', [ '2010-08-12', '12:23:56', 'INFO', '2100', 'some stuff, REPA0.prm: Executing DDL operation.' ], '2100', [ '2010-08-12', '12:23:56', 'INFO', '2100', 'some output, REP.prm: DDL operation is of default scope. +' ],

        With a data structure of an array of arrays, where the first "element" is 2100 in this example,

        I'd like to convert this into a Hash of array of arrays where 2100 is the hash key to an array of arrays.

        %alertlog = map { $_->[0] => [ $_->[2], $_->[3], $_->[4], $_->[5], $_ +->[6] ]; } sort { Date_Cmp($a->[1], $b->[1]) } map { chomp; @loglines = split(/\s+/, $_, 5); $timestring = $loglines[0] . ' ' . $loglines[1]; [ $loglines[3], (ParseDate($timestring), $loglines[0], $lo +glines[1], $loglines[2], $loglines[3], $loglines[4]) ]; } @messages;

        This creates a hash of arrays just fine, but it flattens out the array of arrays.

        In the original array of arrays, the $_->[0] referred to above is always the first element in an array of arrays.

        Below, the "2100" key should show, as it's hash value, an array of arrays....... And likewise for any "key" which has one or more arrays as its resultant value.

        DUMP OF %alertlog from check_alertlog(): $VAR1 = { '109' => [ '2010-08-13', '17:42:58', 'ERROR', '109', 'some stuff, .... SQL <UPDAT...' ], '190' => [ '2010-08-13', '17:42:58', 'ERROR', '190', 'another message ' ], '2100' => [ '2010-08-12', '21:18:53', 'INFO', '2100', 'another message...' ] };

        So, from the array which was passed, and, from which, using map, I'm trying to create a hash of arrays of arrays, the map I've got so far, creates a hash of arrays just fine, BUT it doesn't do a hash of arrays of arrays properly...

        If I make the map output an array of arrays, it works for that just fine and outputs, e.g.,

        $VAR1 = [ [ '2100', '2010-08-12', '15:34:37', 'INFO', '2100', 'bunch of info: Executing operation.' ], [ '2100', '2010-08-12', '15:34:37', 'INFO', '2100', 'bunch of info: operation is of unmapped scope.' ], [ '2100', '2010-08-12', '15:34:37', 'INFO', '2100', 'bunch of info, REP.p: Executing operation.' ],
        If I could take that output, in the map, and make "2100" the hash key to an array of arrays, that's what I am trying to do.. under time pressure so will go back to the docs tonight and keep trying as time and life permit.

Re: Using map to convert an array into a hash of array of arrays
by psini (Deacon) on Aug 10, 2010 at 14:22 UTC

    Try:

    Dumper(\%sorted_msgs)

    Should be more meaningful

    Rule One: "Do not act incautiously when confronting a little bald wrinkly smiling man."