http://www.perlmonks.org?node_id=234104

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

Hi all, I am past the point of braking and in so I turn to the people that will know.

I have looked over the Q/A but unless I missed it I didn’t see an answer?

My problem:
I currently have a hash of arrays. I can find the number of keys in the hash but I wish to find the number of element in each array?

I have constructed the hash using

push @{$FULLLINES{$account}}, “$lines”;
I have managed to count lines using the below solution but I am sure its not ideal. Is there a proper way of doing this? I have tried all different types of array length test and hash length test but I can’t find the one for me.
foreach $key (sort keys %FULLLINES){ $CCOUNT = 0; print "key = $key\n"; if ($key eq "N/A") {next;} foreach $fullline (@{$FULLLINES{$key}}) { $CCOUNT++ } $num = $CCOUNT; if ($num <= 1) { print "account number for $key listed $num times\n"; } else {print "Account $key is listed:$num times\n";}

Replies are listed 'Best First'.
Re: Finding the size of an array in a hash?
by Hofmator (Curate) on Feb 10, 2003 at 13:06 UTC
    my $num = @{$FULLLINES{$key}};

    -- Hofmator

      Thank you very much. Im sure i tried that but Obviously not

      As your suggestion worked first time.

      Thanks again.

      Gareth

(jeffa) Re: Finding the size of an array in a hash?
by jeffa (Bishop) on Feb 10, 2003 at 15:36 UTC
    Hofmater set you straight, but i feel inclined to offer two more tips:
    1. push @{$FULLLINES{$account}}, “$lines”;
      Don't put quotes around $lines -- this is habit that will get you into trouble when you start dealing with references. Besides, the quotes are completely superficial since they will allow the contents to evaluate to the ... contents, namely, the variable $lines. Use this instead:
      push @{$FULLLINES{$account}}, $lines;
    2. Learn how to format. Get a copy of PerlTidy if you have to. Having to count braces to determine where scope starts and ends is no fun for an experienced programmer. If you want to play with the big dogs, dress the part!
    Here is your above code, reformatted for clarity and corrected (you left out the closing brace for the very first foreach).
    foreach $key ( sort keys %FULLLINES ) { $CCOUNT = 0; print "key = $key\n"; next if $key eq "N/A"; $CCOUNT++ for @{$FULLLINES{$key}}; $num = $CCOUNT; if ( $num <= 1 ) { print "account number for $key listed $num times\n"; } else { print "Account $key is listed:$num times\n"; } }
    Oh yeah .... one more tip: USE STRICT! ;)

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
Re: Finding the size of an array in a hash?
by FoxtrotUniform (Prior) on Feb 10, 2003 at 15:53 UTC

    Another thing I haven't seen mentioned yet:

    When dealing with nested constructs like this, I find it useful to dereference each level into a temp variable, rather than sling around nested refs. Makes the code easier to read, brings your assumptions about the data's structure to the front, and prevents problems like this, but at a cost in speed and space. I think it's usually a good tradeoff.

    So you'd have:

    my $lines = $FULLLINES{$key}; my $num = scalar @$lines;

    instead of Hofmator's

    my $num = @{$FULLLINES{$key}};

    It doesn't make a big difference here, but with deeply nested structures it's invaluable.

    --
    F o x t r o t U n i f o r m
    Found a typo in this node? /msg me
    The hell with paco, vote for Erudil!

      I don't know if it makes it more readable, but it sure can slow you down in tight loops. =) I don't find it hard to read HoA AoA etc ulness they get 4 or 5 levels deep I guess.

      -Waswas
          I don't know if it makes it more readable, but it sure can slow you down in tight loops.

        If you want speed, C is --> thataway. As far as I'm concerned (and I speak as a real-time graphics hacker), Perl is for programmer efficiency, not processor efficiency.

        --
        F o x t r o t U n i f o r m
        Found a typo in this node? /msg me
        The hell with paco, vote for Erudil!

Er...
by Nkuvu (Priest) on Feb 10, 2003 at 21:47 UTC
    Correct me if I'm wrong (which wouldn't be too much of a surprise), but isn't
    push @{$FULLLINES{$account}}, “$lines”;
    creating an array of hashes?

    This is a very different thing than a hash of arrays.

      No it is not. It's essentially the same as
      my $aRR = []; push @$aRR, $lines; $FULLINESS{$account} = $arr;
      See what i'm saying?


      MJD says you can't just make shit up and expect the computer to know what you mean, retardo!
      ** The Third rule of perl club is a statement of fact: pod is sexy.

      Actually, push @anything, "$lines" creates an array of scalars, which is why jeffa warns against it--since it may not be what you wanted.

      To your original question, push @{$FULLLINES{$account}}, “$lines”; is populating an anonymous arrayref for key $account in the %FULLLINES hash. %FULLLINES would look something like this:

      ( 'account1' => [ 'lines','lines', ], 'account2' => [ 'lines', ], )

      When in doubt, you can

      use Data::Dumper; print Dumper(\%FULLLINES);
      --
      You said you wanted to be around when I made a mistake; well, this could be it, sweetheart.
        Hrm. I'll have to take your (that's a "your" plural, btw) word for it. This is why I don't use hashes of arrays or arrays of hashes.

        I've had to update some scripts by co-workers who use variables like $rvw (your guess is almost as good as mine on what that variable represents (my only advantage is I have some context)) and insane compositions such as the above (actually the above make the compositions I'm dealing with look like cake sometimes). And of course the previous developer didn't know what a comment was. They're always hard for me to decipher, and are a good indication on why people think Perl looks like line noise...

        Anyway, thanks for the clarification.