Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer

Count of HoA elements

by sweetblood (Parson)
on Jan 19, 2007 at 20:03 UTC ( #595560=perlquestion: print w/ replies, xml ) Need Help??
sweetblood has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to get a total count of elements in a Hash of Arrays, but can't think or anyway short of iterating through the entire hash. I was thinking
my $count = scalar @{ values %hash };
should do it but I get "Can't use string ("###") as an array ref while "strict refs" in use." I know I can get the total by going through the hash and counting the number of elements for each, but would prefer not to.



Comment on Count of HoA elements
Download Code
Re: Count of HoA elements
by BrowserUk (Pope) on Jan 19, 2007 at 20:06 UTC
Re: Count of HoA elements
by Fletch (Chancellor) on Jan 19, 2007 at 20:12 UTC

    Sounds like the typical impossible "I want to do iterative task X without iterating" request. Use List::Util and map and you can hide most of it, though.

    use List::Util qw( sum ); use YAML::Syck qw( Load ); my $hash = Load( do { local $/; <DATA> } ); my $count = sum( map { scalar @{ $hash->{ $_ } } } keys %${hash} ); print $count, "\n"; __END__ foo: - A - B - C bar: - D - E baz: - F - G - H

    Addendum: Just to make things clear: as others have below I'm interpreting "a total count of elements in a Hash of Arrays" to mean "a sum of the count of elements in each arrayref contained in a hash". And just to add more "twaddle", a Ruby version:

    require 'yaml' hash = YAML::load( <<EOT ) foo: - A - B - C bar: - D - E baz: - F - G - H EOT count = hash.values.inject(0) { |s,a| s += a.size } puts count ## O(1) version, akin to ikegami's below o_1_count = 0 hash.each_value { |a| o_1_count += a.size } ## Duuurh, Hash isa Enumerable so it has an inject itself or_even_count = hash.inject( 0 ) { | s, (k,v) | s += v.size }

    Addendum Update: Changed Ruby version to use hash.values rather than hash.keys, as seen below, which is actually a cleaner implementation than mine above. Also added (what should be :) an O(1) Ruby implementation. And also added using Hash#inject directly rather than iterating over values.

Re: Count of HoA elements
by ikegami (Pope) on Jan 19, 2007 at 20:15 UTC

    should do it

    No, it shouldn't. @{...} expects that ... retunrns a reference to an array. values %hash does not.

    anyway short of iterating through the entire hash.

    What do you think values does? Returns a list obtained by iterating through the entire hash.

    And whatever processes the list returned by value has to iterate over that list.

    These work:

    # time = O(N) memory = O(N*M) my $count = map @$_, values %h;
    # time = O(N) memory = O(N) my $count = sum map { scalar @$_ } values %h;
    # time = O(N) memory = O(N) my $count = 0; $count += @$_ for values %h;
    # time = O(N) memory = O(1) my $count = 0; while (my ($k, $v) = each(%h)) { $count += @$v; }

    Added 2nd and 4th solution.
    Added time and memory analysis.
    Choose the one that's the most readable and maintainable within your speed and memory requirements.

        He asked for the number of elements in the HoA. I took that to mean 5 for the following structure:

        my %h = ( k1 => [ qw( a b c ) ], k2 => [ qw( d e ) ], );

        Your solution simply returns the number of elements in a hash. It could be that's what he meant, but that's now how I interpreted his question.

        This is wrong.

        Not so hasty on the wrong. Fletch and Jenda also interpreted the question like I did.

      Though I would not recomend using the second on big datastructures as it builds a list of all the elements in the arrays in the hash. Use either the first solution or

      use List::Util qw(sum); my $count = sum map scalar(@$_), values %h; #or # my $count = sum( map scalar(@$_), values(%h)); # or # my $count = sum( map {scalar(@$_)} values(%h)); # if that syntax looks more readable to you.

      Regarding the update: the first solution uses O(N) of memory where N is the number of elements of the hash, the second O(N*M) where M is the average length of the array in the hash. The List::Util solution is also O(N) memorywise.

Re: Count of HoA elements
by cormanaz (Chaplain) on Jan 19, 2007 at 22:11 UTC
    How about

    my $count = keys(%hash);


      Number of elements in a HoA $#{ $table{$ent}}

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://595560]
Approved by ww
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others having an uproarious good time at the Monastery: (8)
As of 2014-12-21 09:16 GMT
Find Nodes?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?

    Results (104 votes), past polls