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

Given a two dimensional hash, is there a way to return
the number of subkeys from that hash WITHOUT LOOPING?
Key and subkey names are variable lvalues. Key hashes may
contain any number of subkeys or none at all (null):
%hash = ( key1 => { subkey1 => value1, subkey2 => value2, ... }, key2 => { }, key3 => { subkey1 => value1, }, ... );

What I'm looking (hoping) for is something like: "scalar subkeys %hash".

Grazie mille!
"Dogs love me cuz I'm crazysniffable / I bet you never knew I got the ill peripherals"

Replies are listed 'Best First'.
Re: scalar subkeys %hash ?
by srawls (Friar) on Jun 14, 2001 at 03:58 UTC
    This is all I could come up with; sorry though--it loops.
    $numSubKeys=map{keys %{$hash{$_}} }keys %hash

    The 15 year old, freshman programmer,
    Stephen Rawls

      Hey, that's was pretty slick. crazysniffable, if you're not sure what's going on, here's the scoop:

      The map operator takes an array and loops over each element. In this case, the array is the keys of %hash. In srawls' code for map, he's asking for it to return the keys to the anonymous hash at $hash{$_}. Since he's evaluating it in scalar context, it returns the total number of elements, instead of the keys. This code is equivalent to:

      my $numSubKeys = 0; foreach ( keys %hash ) { $numSubKeys += scalar keys %{$hash{$_}} }; }
      Of course, as srawls mentioned, it loops. There's really no way around this (that I can see).

      Cheers,
      Ovid

      Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

        I concur with Ovid on srawls' solution: very slick indeed.

        The reason I'm trying to get at a scalar value for the subkeys
        in a %HashOfHashes without looping is because I'm already
        iterating through the keys/subkeys.

        What I'm really trying to do: given a %HoH, iterate through
        the subkeys and display each $interval group of subkeys
        (where $interval is a positive integer). Of course, when
        I get to the end, I'll need to kick out the last group even
        though the counter never gets to $interval.

        Example and pseudocode: my %HoH contains 97 subkey-value pairs
        (but I don't it's 97).

        $interval = 10; foreach $key (keys %HoH) { if ($interval % $counter == 0) { display(\%tmp); $counter = 0; # reset the counter } foreach $subkey (keys %{$HoH{$key}}) { $tmp{++$counter} = "$key -- $subkey"; } }
        The problem I run into is when $counter is a remainderless
        divisor of $interval (ie, $counter = 1). I can kludge around
        this obstacle by doing a sort of --$secondary_counter decrement
        if I knew the total number of subkeys with which I could compare
        $secondary_counter. This is where srawls' golfing looks great
        but then I'd be iterating over the hash twice.

        Muchas gracias,
        "dogs luv me cuz i'm crazy sniffable / i bet you never knew i got the ill peripherals"

      Or more idiomatically:
      $numSubKeys = map keys %$_, values %hash;
         MeowChow                                   
                     s aamecha.s a..a\u$&owag.print
        Nice... At first I tried that, only I forgot to put values %hash instead of keys. Oh well.

        Oh, and if this were a golf, I could improve that by 2 chars:

        $n=map keys%$_,each%h

        Update:Whoops, as MeowChow pointed out, this doesn't work for hashes with more than one key.

        The 15 year old, freshman programmer,
        Stephen Rawls

(Ovid) Re: scalar subkeys %hash ?
by Ovid (Cardinal) on Jun 14, 2001 at 03:36 UTC

    You need to dereference the hash:

    %hash = ( key1 => { subkey1 => 'value1', subkey2 => 'value2', subkey3 => 'Ovid' } ); print scalar keys %{$hash{ key1 }};

    Cheers,
    Ovid

    Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

      While your suggestion works, it only gives me subkeys for
      the first subhash (key1). Can I get the number of all the subkeys?

      However, I should've been more code specific in that the key
      and subkey names are variables:

      %hash = ( variable_key_name => { variable_subkey_name => somevalue, another_var_subkey => someothervalue, ... }, another_variable_key_name => { variable_subkey => somevalue, variable_subkey2 => anothervalue, ... }, ... );

      Merci beaucoup!