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

Hi all, I am new to Perl and having difficulty solving a problem. I'm trying to:
-take a few files of text as input
-pare the text down to reveal only a license plate i.d. that is three letters and three numbers, e.g., ABC 123
-license plates are "grouped" (for output) according to their letter sequence, so proper output would look like:
ABC 123, 334, 442
FTE 442
HHR 443
NTR 554, 554
I'm mostly having trouble making a hash of a hash. I know that it can be done with a hash of arrays (which I also was having trouble with), but I want to do it with a hash of hashes, if possible. Here's my code:
#! usr/bin/perl while (<>) { $input = $_; #I strip the raw input of extraneous info to #get the letters and numbers which are each #made into variables #This part of the code is working well and is thus omitted $lets = $input; $nums= $input; $plates{$lets} = $nums{0}; } foreach $licPlate (keys %plates) { print "$licPlate "; }
I had it where it was printing the same license plate numbers for all entries, but I changed the code and am not sure how I was even doing that. How do I properly make a hash of a hash from inputted files? How do I then output this in the form I showed above? I see how to get the keys out for the letter part of the license plates, but I'm stuck with how to show more than one set of numbers per letter group, or how to get each plate number to print out instead of one plate number printing out for each letter group. Thank you very much for any help given!

Replies are listed 'Best First'.
Re: hash of hashes
by GrandFather (Saint) on Mar 23, 2007 at 22:30 UTC

    A hash of hashes is exactly appropriate to your problem. The code below counts the number of times each plate has been seen, but if vehicle information needed to be associated with plates then that could become the value rather than a count:

    use strict; use warnings; my %plates; while (<DATA>) { chomp; next if ! /(\w+)\s+(\d+)/; ++$plates{$1}{$2}; } for my $group (sort keys %plates) { print "$group ", join ', ', sort {$a<=> $b} keys %{$plates{$group +}}; print "\n"; } __DATA__ ABC 334 NTR 557 ABC 442 FTE 442 HHR 443 NTR 554 ABC 123

    Prints:

    ABC 123, 334, 442 FTE 442 HHR 443 NTR 554, 557

    DWIM is Perl's answer to Gödel
      Sorry I've taken so long to say thank you for your help. Everything works swimmingly now! Gracias!
Re: hash of hashes
by Anno (Deacon) on Mar 23, 2007 at 21:28 UTC
    I know that it can be done with a hash of arrays (which I also was having trouble with), but I want to do it with a hash of hashes, if possible

    Why on earth would you want to do that? For each letter sequence you want the list of numbers that were associated with it. That shouts for a hash of arrays.

    In the loop, when you have $lets and $nums, collect the numbers belonging to $lets:

    push @{ $plates{ $lets} }, $nums;
    To print the results:
    print "$_ ", join( ', ', @{ $plates{ $_}), "\n" for sort keys %plates;
    (Code untested)

    Anno

      Why on earth would you want to do that?
      You'd want to do that in perl if the original input contains duplicates and you only want to show unique license plate numbers. Since perl doesn't have a built-in concept of a (uniqe) set hashes are the natural structure to use.

      To the OP: note that i use sort here, but that's just because I presume you'd want the output to be predictable.

      $plates{$lets}{$number} =1; # or $plates{$lets}{$number}++ if you wan +t to count # and for my $let (sort keys %plates) { print "$let ",join(", ",sort keys %{$plates{$let}}),"\n"; }
      Updated: removed map() - code should now be correct
        Hi Joost,

        You are correct that I am using a hash of hashes because of duplicates. The program will be reading multiple files, many of which will contain the same license plate.

        I'm going to try your code now and will report back shortly.

        Many thanks! 8^}
        Well, the OP said

        proper output would look like:

        ABC 123, 334, 442 FTE 442 HHR 443 NTR 554, 554

        Note the last line, which shows a duplicate number.

        I have seen the OPs reply that confirms that duplicates are indeed unwanted. The sample output seemed to indicate the opposite.

        Anno