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

Currently my code destruct a hash in HoH in order to achieve it's goal (see result). How can I make it non destructive?
#!/usr/bin/perl -w use strict; use Data::Dumper; my %HoH = ( 'pk1' => { 'sk1' => [ 'val1', 'val2' ], 'sk2' => { 'tk1' => 'val1 val2 ', 'tk2' => 'val9,val7' }, 'sk3' => 'val10 val11', 'sk4' => 21 }, 'pk2' => {}, 'pk3' => { 'sk1' => [ 'val1', 'val2' ], 'sk2' => { 'tk1' => 'val1 val2 ', 'tk2' => 'val9,val7' }, 'sk3' => 'val2 val3', 'sk4' => 30 }, ); foreach my $k ( keys %{HoH} ) { unless ( $HoH{$k} and values %{$HoH{$k}} ) { delete $HoH{$k}; } } my @best_inst; #AoA my @best_key = sort { $HoH{$b}->{'sk4'} <=> $HoH{$a}->{'sk4'} + } keys %HoH; #print Dumper \@best_key; push (@best_inst, $HoH{$best_key[0]}->{'sk4'}, $HoH{$best_key[0]}->{'sk1'}, $HoH{$best_key[0]}->{'sk2'}, $HoH{$best_key[0]}->{'sk3'} ); print Dumper \@best_inst;
Prints (get the top 1 ):
$VAR1 = [ 30, [ 'val1', 'val2' ], { 'tk2' => 'val9,val7', 'tk1' => 'val1 val2 ' }, 'val2 val3' ];

readmore tags added by holli

Replies are listed 'Best First'.
Re: How not to destroy a Hash in HoH
by jhourcle (Prior) on Jun 15, 2005 at 11:49 UTC

    You just need to change your logic, so you make a copy when you find something you like, rather than delete everything that you don't like.

    replace:

    foreach my $k ( keys %{HoH} ) { unless ( $HoH{$k} and values %{$HoH{$k}} ) { delete $HoH{$k}; } }

    with :

    my %HoHCopy; foreach my $k ( keys %HoH ) { if ( $HoH{$k} and values %{$HoH{$k}} ) { $HoHCopy{$k} = $HoH{$k}; } }

    and then replace the calls to %HoH to %HoHCopy below that.

    You could also change that same block out with:

    my %HoHCopy = map { $_ => $HoH{$k} } grep { $HoH{$_} and values %{$HoH{$_}} } ( keys %HoH ); # or my %HoHCopy = map { ($HoH{$_} and values %{$HoH{$_}}) ? ($_ => $HoH{$k}) : () } ( keys %HoH );
      thanks so much jhourcle,

      I have further question to ask for your opinion:
      1. Which is better destructing the hash or not? Will it improve performance significantly?
      2. What is your rule of thumb? Given the choice "to destroy or not to destroy"
        The answer is, of course,    It depends.

        Are you going to ever use that data for something else? Then don't delete. Are you exiting as soon as you find the stuff you want and operating on it? Then don't delete, you're just wasting the CPU's time when its ALL going to be deleted from memory when the program exits anyway.

        The ONLY time deleting makes sense is if the script will continue to run, and it's accumulating a lot of stuff, and continuing to operate on all the "good data". If this is the case, then yes, deleting the non-useful information will save memory, and is thus a good idea.

        -Scott

        I'm going to go with the 'it depends' answer, but with slightly different thoughts on it than 5mi11er --

        Why do I want the data subset?
        If I'm removing problem data, and I don't want anything else that might act on the data to see the problem items, then I'll remove them, rather than making a copy. If it's just a reduction for the task at hand, but something else is going to need the whole data set, then I'm going to work on a copy.
        Why was this hash created?
        If it was created just for the task and hand, or I'm not going to need it for anything else once I'm done (the program will terminate, etc), I'll trim it down to the entries I care about, rather than keeping it in memory, with a copy of the trimmed down version.
        Am I in a function?
        If the hash was passed in as a reference to a function, unless the function is specifically named in such a way as to suggest that it's modifying its arguments (eg, 'remove_invalid_values'), I'm going to make a copy, as I have no idea how people might chain things together later. Typically, if I'm in a function, I'll just return out the copied hashref, so that the code calling the function can decide if they want to trash the original:$hashref = valid_values( $hashref );

        As for a rule of thumb -- given a choice between destroy, and not destroying, I'm going to get rid of stuff that I don't need anymore as quickly as possible.

        You can, however, run into problems -- when you wrote the code, it was the last thing in the program... but someone went and added something new at the bottom, and can't understand why the values they wanted are now missing.

Re: How not to destroy a Hash in HoH
by kwaping (Priest) on Jun 15, 2005 at 14:54 UTC
    I just want to commend you on your excellent use of whitespace in your code. It was more readable than most of what I see posted here. ++ :)