in reply to Re: Perl Hash
in thread Perl Hash

thanks Dave, well I think I'm populating the hash now, but cannot prove it as I have a problem with the print loop
my $HashKey = $_[4]; $HashKey += 1; # initialise the hash my %LogHash = (); while (<LOGFILE>){ if (/\b$Autosys/) { # populate the hash %LogHash = ($HashKey => $SentRec = substr($_, 0, 20)); } } # debugging stub # print out the contents of the hash foreach $k (keys(%LogHash)) { print LOGFILE $k, ",", $LogHash{$k}, "\n"; }
the error is
Global symbol "k" requires explicit package name at ./pmc_tester.pl li +ne 183. Execution of ./pmc_tester.pl aborted due to compilation errors.
So I'm not there yet...

Replies are listed 'Best First'.
Re^3: Perl Hash
by davorg (Chancellor) on Jul 26, 2005 at 09:12 UTC

    You've obviously got "use strict" in your program (which is a good habit to get into) so you need to predeclare[1] all of your variables.

    foreach my $k (keys(%LogHash)) { print LOGFILE $k, ",", $LogHash{$k}, "\n"; }

    Oh, but there's no need to make that print statement so complex.

    foreach my $k (keys(%LogHash)) { print LOGFILE "$k, $LogHash{$k}\n"; }

    [1] Or fully qualify their names, but let's not get into that :)

    --
    <http://www.dave.org.uk>

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

Re^3: Perl Hash
by reasonablekeith (Deacon) on Jul 26, 2005 at 09:21 UTC
    I'm afraid this whole script is a bit confused. You really should read up on hashes. There are much better explanations available than I could give here.

    Anyway, with that said, you get an error because you've not delcared $k in your foreach loop ala...

    foreach my $k (keys(%LogHash)) { print LOGFILE $k, ",", $LogHash{$k}, "\n"; }
    Your also emptying your hash with the line...
    %LogHash = ($HashKey => $SentRec = substr($_, 0, 20));
    assigning a key with a value would normally be done like this
    $LogHash{%HashKey} = "THEVALUE";
    ... but this isn't going to help you much because I'm still not sure what the output of the program should be.

    You also seem to think that you can have multiple values for a single key. That's not true, hashes are one key -> one value (that's not to say the value couldn't be an array reference, but that's a whole other topic).

    you might also want to take a look at data::dumper, which is great for debugging hashes (by printing them)

    use Data::Dumper; print Dumper(\%hash);
    good luck
    ---
    my name's not Keith, and I'm not reasonable.
      thanks Dave, I've got past the "not declaring my $k further up the program" problem now :)

      but it appears my problem is what "not Keith" says

      >> You also seem to think that you can have multiple values for a single key. That's not true,

      well in that case, I do have a problem as I want to store several lines of text against the same key like this



      KEY1 07/25/05 09:04:36 KEY2 07/25/05 09:04:36 KEY2 07/25/05 09:04:37 KEY2 07/25/05 09:05:49 KEY2 07/25/05 09:05:50 KEY3 07/25/05 09:05:50


      so then I can find the earliest time in KEY2 is 09:04:36 and the latest time is 09:05:50

      However, now I'll have to find another way.

      Thanks for your help.
        I want to store several lines of text against the same key

        Then you want the values in your hash to be array references.

        You should probably read perldsc.

        --
        <http://www.dave.org.uk>

        "The first rule of Perl club is you do not talk about Perl club."
        -- Chip Salzenberg

        A Hash of arrays may fit the bill for you:

        use strict; use warnings; use Data::Dumper; my %HoA; while (<DATA>) { chomp; next if ! length $_; my ($key, $time) = split ","; push @{$HoA{$key}}, $time; } print Dumper (%HoA);

        Perl is Huffman encoded by design.

        or if you rather just retain the first and last time for each key for which there is more than one time:

        use strict; use warnings; use Data::Dumper; my %HoA; while (<DATA>) { chomp; next if ! length $_; my ($key, $time) = split ","; if (! $HoA{$key}) {push @{$HoA{$key}}, $time;} elsif (@{$HoA{$key}} == 1) {push @{$HoA{$key}}, $time;} else {${@{$HoA{$key}}}[1] = $time;} } print Dumper (%HoA);

        Perl is Huffman encoded by design.

        As your data looks to be time sequential something easy like this would probably do you fine. I have given a simple way to do it with two hashes or a more perlish way with a hash of arrays. If your data lines are not ordered by time then a check to compare two time stamps will be needed for each line to decide if to update first or last time.

        #!/usr/opt/perl5/bin/perl use strict; use warnings; use Data::Dumper; my %earliest; my %latest; my %hash_of_arrays; my $line; while ($line = <DATA>) { chomp $line; # remove return my ($key, $date) = split /\s+/, $line, 2; # split on space into ma +x 2 parts next unless $date; # ignore blank or malfor +med lines unless (defined $earliest{$key}) { $earliest{$key} = $date; } $latest{$key} = $date; # or with a hash of arrays $hash_of_arrays{$key} or $hash_of_arrays{$key}[0]=$date; $hash_of_arrays{$key}[1]=$date; } print Data::Dumper->Dump([\%earliest], ['%earliest']) ; print Data::Dumper->Dump([\%latest], ['%latest']); print Data::Dumper->Dump([\%hash_of_arrays], ['%hash_of_arrays']); print "first time for KEY1 was: $hash_of_arrays{KEY1}[0]\n"; print "last time for KEY1 was: $hash_of_arrays{KEY1}[1]\n"; __DATA__ KEY1 07/25/05 09:04:36 KEY2 07/25/05 09:04:36 KEY2 07/25/05 09:04:37 KEY2 07/25/05 09:05:49 KEY2 07/25/05 09:05:50 KEY3 07/25/05 09:05:50 KEY1 07/25/05 09:06:36 # output =>./first $%earliest = { 'KEY2' => '07/25/05 09:04:36', 'KEY1' => '07/25/05 09:04:36', 'KEY3' => '07/25/05 09:05:50' }; $%latest = { 'KEY2' => '07/25/05 09:05:50', 'KEY1' => '07/25/05 09:06:36', 'KEY3' => '07/25/05 09:05:50' }; $%hash_of_arrays = { 'KEY2' => [ '07/25/05 09:04:36', '07/25/05 09:05:50' ], 'KEY1' => [ '07/25/05 09:04:36', '07/25/05 09:06:36' ], 'KEY3' => [ '07/25/05 09:05:50', '07/25/05 09:05:50' ] }; first time for KEY1 was: 07/25/05 09:04:36 last time for KEY1 was: 07/25/05 09:06:36

        Cheers,
        R.

        Pereant, qui ante nos nostra dixerunt!
        Is it necessary to use hashes or more complicated data structures? What about simple array?
        my @times; while (<LOGFILE>){ if (/\b$Autosys/) { push @times, substr($_, 0, 20); } }

        Update: yes, you can downvote me, 'cause HoA is the best way here. I misunderstand post. Shame on me.