Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

Determine largest key in hash

by Anonymous Monk
on Oct 04, 2011 at 17:21 UTC ( #929604=perlquestion: print w/ replies, xml ) Need Help??
Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi everyone.

I'm trying to create a hash (or rather a HoH I believe) and need some assistance.
%hash = ( 1 => { 1 => "", #dynamically created name => "", that => "", }, 2.... # iteration );
Above is what my hash structure looks like. It is dynamically built as I'll never know how deep or how many items there will be. The tricky part for me is the first "1" in the example above is an iterator. On particular iterations through my loop if it == that number, I need to look into that hash's data.

The second "1" is where I dynamically lable my items and the other attributes. My question is, how do I determine the greatest number that exists so I know what the next one has to be? Pretend we need to create another event under iterator count 1. I know how to check existance to see if it is defined, I just don't know the easiest way to see the highest count if I need to build more.
$hash{1}{1} = "blah"; $hash{1}{2} = "blah";
In the above, how could I detect {2} as the highest number so I know to start at {3} next time something is added?

In short, each iterator count could have more than one "event" and I need a way to record as many events as necessary. That way I only have to look up $hash{$num} to see all the events that take place for that iteration.

Comment on Determine largest key in hash
Select or Download Code
Re: Determine largest key in hash
by BrowserUk (Pope) on Oct 04, 2011 at 17:33 UTC

    At any given level, keys (as in my $n = keys %{ $hashref };) will tell you how many elements exist at that level.

    Which if the only keys in the hash were the numeric ones, then that would tell you what number to use for the next insertion. But in that case, you'd be far better off using an array rather than a hash.

    But for the second level in your structure, where you have other, non-numeric keys, then that won't work. But then, if you added a key '2' at that level, where are you going to store the associated 'name' & 'that'? Because if you try to store them as you have the first set, you'll just overwrite them.

    Bottom line is that you almost certainly need to review your data structure.

    Perhaps if you outlined what the data was and where it came from, we might be able to help you with that.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Hi.

      Thank you for the response. I can give an overview of what I'm trying to do.

      Pretend have a loop
      my $cnt = 0; while(1) { $cnt++; #print event trigger from hash }
      At every iteration I need to check to see if I have an "event trigger" in the hash. If I do, I need to print it. I can't do a simple hash because each iteration (of the counter) COULD have more than one event trigger.
      my %hash = ( 1 => { 1 => "nothing", name => "Shrek", event => "I saw shrek!", }, 6 => { 1 => "nothing", name => "Donkey", event => "I saw the donkey!", 2 => "nothing", name => "Fiona", event => "I saw Fiona!" }, );
      So on our first iteration we'd get triggered that we found Shrek. Sweet! It works well because we only had the one event.

      However for the 6th time through the loop we have TWO events. That is why I need to numerically index them because I never know.. maybe an event happens in my code and I need to create a third or fourth event for iteration 6 and I need them ALL to work properly.

      So the numerics are only for use in determining which iteration to come out on, and then they are used to allow me to use as many events as necessary (the event names in the real code are NOT unique so I would not be able to use the names of them. Numbers were the only thing I could think of to make this work.

        Ok, Given that use, I would probably do either a sparse array, or a *cringe* hash with numeric keys. Please note that your data under each first level key is not correct...

        my %hash = ( 1 => [ { name => "Shrek", event => "I saw shrek!" }, ], 6 => [ { name => "Donkey", event => "I saw the donkey!" }, { name => "Fiona", event => "I saw Fiona!" }, ], );

        You would access this stuff then with....

        for my $trigger ( @{ $hash{$cnt} || [] } ) { # Do work here with $trigger .... }

        See Re: Determine largest key in hash for details on how to push data into the trigger list.

        As a sparse array, this would look like...

        my @data = ( [ # 0 (remember, we are zero-based) { name => "Shrek", event => "I saw shrek!" }, ], undef, # 1 undef, # 2 undef, # 3 undef, # 4 [ # 5 - zero-based => 6th element { name => "Donkey", event => "I saw the donkey!" }, { name => "Fiona", event => "I saw Fiona!" }, ], );

        You would change your loop to...

        for my $trigger ( @{ $data[$cnt-1] || [] } ) { # Do work here with $trigger .... }

        I still have a little bit of a cringe-factor with the layout of the sparse array, and would probably reevaluate the control logic around that, but this shows a couple of ways where the structure can make quite a difference in how you manage your data.

        --MidLifeXis

        That will not work. You build a hash like this:

        [0] Perl> %hash = ( 1 => { 1 => "nothing", name => "Shrek", event => "I saw shrek!", }, 6 => { 1 => "nothing", name => "Donkey", event => "I saw the donkey!", 2 => "nothing", name => "Fiona", event => "I saw Fiona!" }, );;

        But end up with this:

        pp \%hash;; { 1 => { 1 => "nothing", event => "I saw shrek!", name => "Shrek" }, 6 => { 1 => "nothing", 2 => "nothing", event => "I saw Fiona!", name + => "Fiona" }, }

        NOTE: that in the hash key by '6' there is only one 'name', and only one 'event'.

        You cannot have duplicate keys in a hash. You need to rethink your data structure.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Determine largest key in hash
by blue_cowdawg (Monsignor) on Oct 04, 2011 at 17:34 UTC

    sub findMaxKey { my @rry=@_; my $max=0; foreach my $ix(@rry){ $max = $ix if $ix > $max; } return $mx } my $maxkey = findMaxKey(keys %hash);


    Peter L. Berghold -- Unix Professional
    Peter -at- Berghold -dot- Net; AOL IM redcowdawg Yahoo IM: blue_cowdawg
Re: Determine largest key in hash
by MidLifeXis (Prior) on Oct 04, 2011 at 17:39 UTC

    Is there a reason to use a hash instead of an array for the first layer (update: or even the dynamic data)?

    @data = ( { # Not quite certain what purpose this serves # 1 => "", #dynamically created # Perhaps something like this instead... dynamic_data => [ ... ], name => "", that => "", }, # ... and so on );

    Then, your code would instead be ...

    push @{ $data[0]{dynamic_data} }, "blah"; push @{ $data[0]{dynamic_data} }, "bleh";

    I would rename dynamic_data to something more descriptive, of course.

    Perhaps a description or example of how you use the data or what it represents might help shake out an appropriate data structure.

    --MidLifeXis

Re: Determine largest key in hash
by tj_thompson (Monk) on Oct 04, 2011 at 17:41 UTC

    Assuming you know the first key, you have a few simple options. The first first is to pull the keys from the nested hash and do a search through them.

    my $max_event; map {$max_event = $_ if $_ > $max_event} keys %{$hash{1}};

    You can then use $max_event to determine what your next event should be.

    If you have to do this many times, I would suggest an additional field in your hash that tracks the max event like so:

    %hash = ( 1 => { 1 => "", #dynamically created name => "", that => "", current_max => 1, }, 2.... # iteration );

    Now if you need to know the current highest event, you just examine $hash{1}{current_max}. You'll have to ensure that you increment this field each time you add an event.

    This approach could be a problem if the event could have a valid data field named current_max. In this case, you will have to modify your data structure to ensure that the current_max field is cleanly separated from the event data. But it would otherwise work the same.

      Clever and simple. I didn't think about going at it this way.. I think that will work perfectly. Thank you!

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (16)
As of 2014-11-25 21:13 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My preferred Perl binaries come from:














    Results (158 votes), past polls