Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations wOOdy-Soft on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

a better way of switching data between hash values? 1

Status
Not open for further replies.

1DMF

Programmer
Jan 18, 2005
8,795
GB
hi,

I am using the following to switch data from client2 to client1 and blanking client2.

Just wondered if there was a better way...
Code:
                    foreach my $key1 (@{$self->{C1_DATA}}){
                        my $key2 = $key1;
                        $key2 =~ s/1/2/g;
                        $self->{CASE}{$key1} = $self->{CASE}{$key2};
                        $self->{CASE}{$key2} = undef;
                    }

cheers, 1DMF

"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"

Google Rank Extractor -> Perl beta with FusionCharts
 
I take it this is the best way then ?

"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"

Google Rank Extractor -> Perl beta with FusionCharts
 
Your problems are always interesting, 1DMF, but not always there is a satisfying answer...
Note also that
[tt]$self->{CASE}{$key2} = undef;[/tt]
does not delete the key value, you still get it with [tt]keys@...[/tt].
If you want to free space and let the key value in the hash disappear, you should do
[tt]delete$self->{CASE}{$key2};[/tt]
Also there is something strange in your code: [tt]$key1[/tt] is the actual key, [tt]$key2[/tt] the new one, didn't you reverse the keys in
[tt]$self->{CASE}{$key1} = $self->{CASE}{$key2};[/tt]
?
To split hairs, this could be (very) slightly more efficient (to be confirmed by test):
Code:
$tmp=$self->{CASE}{$key1};
delete$self->{CASE}{$key1};
$self->{CASE}{$key2}=$tmp;

Franco
: Online engineering calculations
: Magnetic brakes for fun rides
: Air bearing pads
 
Hey Franco,

No I'm not trying to free space, code throughout uses 'defined' and '! defined' to exclude keys with no value, but thanks for the info, never knew I could use the keyword 'delete' with a hash!

Also there is something strange in your code: $key1 is the actual key, $key2 the new one, didn't you reverse the keys in
You're missing this
Code:
 $key2 =~ s/1/2/g;

The data hash keys are...

C1_Title
C1_Firstname
C1_Lastname

etc..

So basically I'm making C1_xxx = C2_xxx and then blanking C2_xxx.

Intrerestingly though, how much space does deleting a key from a hash save, is there that much benefit?

All these hashes and there are a few are all stored in a class attribute $self->{CASE};

I am looping a records set and after processing each record I set $self->{CASE} = undef;

I am assuming that all the dimensions be they arrays or hashes stored in $self->{CASE} are garbage collected before I assign the next record to the $self->{CASE} attribute.

I take this is what happens, or should I do something else to kill the contents of the class attibute $self->{CASE}











"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"

Google Rank Extractor -> Perl beta with FusionCharts
 
Setting [tt]$self->{CASE} = undef;[/tt] should free all the space reserved for the subkeys and their associated values, just because [tt]$self->{CASE} = undef;[/tt] does not contain anymore, as its value, the reference to a subhash.
However deleting a hash key (with the associated value) has not only the benefit of freeing memory, but also it makes the code faster, as there are less hash keys to search in when a hash value is required.

Franco
: Online engineering calculations
: Magnetic brakes for fun rides
: Air bearing pads
 
Right so as the object hash {CASE} no longer points to it's sub hashes they are freed up, cool!

I'm not sure the record set contains enough hash data to worry about deleing the odd hash key/value.

Unless you are saying it will run MUCH faster?

Writing code to loop the hash getting the redundant keys and deleting them is going to take processing power any way, so would one process cancel out the other?

"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"

Google Rank Extractor -> Perl beta with FusionCharts
 
If it is MUCH faster, it depends on how many keys are in the hash: I think MANY keys would be in the order of 1000 or more.
But you don't need extra processing power: just replace
[tt]$self->{CASE}{$key1}=undef;[/tt]
with
[tt]delete$self->{CASE}{$key1};[/tt]
Then you don't need to loop through the keys, taking only those that have a defined value: you simply won't see anymore the deleted keys (if this suits you).

Franco
: Online engineering calculations
: Magnetic brakes for fun rides
: Air bearing pads
 
well the whole application (object) might have that many, there are a lot of keys in different hashes but not in the {CASE} one, there is @ 50 key/value pairs.

I think I will scour my code and see where I can delete unwanted keys, at the end of the day I'm looking for as much efficiency as possible in application.

I've done a tonne of refactoring now that I have got my head round this OOP milarky so I'm pleased with the progress, tidying up loose ends such as unneccesary keys certainly cant hurt!

Much obliged for your time Franco :)

"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"

Google Rank Extractor -> Perl beta with FusionCharts
 
just looking about and found this...
Code:
    foreach my $key (keys %{$self->{CASE}}){
        # exclusions                  
        if (! exists {map { $_ => 1 } @{$self->{'EXCLUDED_DATA'}}}->{$key}){
            
            # add if data exists
            if (defined $self->{CASE}{$key}){  
                       
                # columns
                $cols .= $key . ',';
            
                # values
                if (exists {map { $_ => 1 } @{$self->{NUMERIC_DATA}}}->{$key}){
                    $vals .= $self->{CASE}{$key} . ',';
                }
                else{
                    my $val = $self->{CASE}{$key};
                    $val =~ s/\'/\'\'/g;
                    $vals .= "'$val',";                    
                }
                
            }            
        }        
    }

Which builds my SQL string for me, there is a class array containing those key/value pairs which are not wanted for the SQL insertion, hence the
Code:
(! exists {map { $_ => 1 } @{$self->{'EXCLUDED_DATA'}}}->{$key}){

there are 24 keys/value pairs in the exclusion is it worth deleting them instead?

"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"

Google Rank Extractor -> Perl beta with FusionCharts
 
Things are becoming complex!
I'm not sure to understand what this
[tt]!exists{map{$_=>1}@{$self->{'EXCLUDED_DATA'}}}->{$key}[/tt]
does, as I normally use the notation [tt]$$self{EXCLUDED_DATA}[/tt] for [tt]$self->{'EXCLUDED_DATA'}[/tt].
Anyway if the array [tt]@{$self->{'EXCLUDED_DATA'}}[/tt] is used many times in your code, it would help to transfer it into a temporary real array, obviously discarding any undefined values in it (the same for NUMERIC_DATA).
And if you discard (delete) all unused keys in [tt]$self->{CASE}[/tt] you can avoid the [tt]if (defined $self->{CASE}{$key}){[/tt], but for a few dozens of keys all this doesn't count much.
Anyway, as I told above, things are becoming complex...%-)

Franco
: Online engineering calculations
: Magnetic brakes for fun rides
: Air bearing pads
 
Hey Franco,

The whole application is rather complex as is its purpose ;-)

doesn't ..

$$ dereference a scalar
@$ dereference an array
%$ dereference a hash

So
Code:
 if(!exists{map{$_=>1}@{$self->{'EXCLUDED_DATA'}}}->{$key}){...}
is derefrencing the anonymous class atribute array 'EXCLUDED_DATA', and maping it into a hash so the keyword 'exists' well 'not exists' in this case can be performed against it.

the 'EXCLUDED_DATA' is a class attribute array, and is constantly used as the recordset is processed it never contains empty values, only $self->{CASE} contains unwanted keys/values as $self->{CASE} is a hash reference to a single record out of the record set (a hash basically).

It is also a helper module (superclass) and many other OOP modules use it in an is a / has a relationship.

I thought that to create class attributes in an OOP manner in perl you use the following syntax...
Code:
# Class Constructor new()
sub new {
   
    # class variable
    my $class = shift;      
    
    # object attributes
    my $self = {
       
        @_,              
        TODAY               => '',
        TIME                => '',                        
        ERRORS              => 0,
        [b]EXCLUDED_DATA       => [
                            'title',
                            'firstname',
                            'lastname'[/b]
                           ]                
    };

     
    # Bless the data structure, making it a true object
    bless ($self,$class);


    # Return the object to the calling program.
    return $self;
}

Am I doing something wrong?

"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"

Google Rank Extractor -> Perl beta with FusionCharts
 
Sorry, I don't use OOP, I think it to be often used to write pretentiously elegant but needless code...[blush]
Coming back to efficiency, and taking this as an example of how apparently elegant code may be less effective:
if
[tt]$self->{'EXCLUDED_DATA'}[/tt] contains static data
and
it contains only single words
this would be dramatically more efficient
Code:
  #at start of code (BEGIN section?)
$excluded_data=" @{$self->{'EXCLUDED_DATA'}} ";
  #to check if a key is not excluded
if(index($excluded_data," $key ")==-1){
However this would be important only if that section of code is used many times during processing.

Franco
: Online engineering calculations
: Magnetic brakes for fun rides
: Air bearing pads
 
Sorry, I don't use OOP, I think it to be often used to write pretentiously elegant but needless code...
really? I'm loving it, not sure if my code can ever be classed as pretentious or elegant though [lol]

It has made me think differently however and write code that is reusable and scalable just like object orientated programing is meant to make you think and code.

anyway, back to your code... It is taking the array, building a concatenated string and then searching the string for a match.

I'm going to run a test with a timer, the current way and your way, lets see how much difference it does make.

As these modules will be run as overnight jobs and I'm hoping they will take no longer than 15 minutes max, so every second saved when ran in production will be worth while.





"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"

Google Rank Extractor -> Perl beta with FusionCharts
 
Well the script runs so fast there is no difference just by using 'time'.

but I can see how more efficient it is having it as a static string and then checking the index of a match.

So although I initially set it as an array for ease of adding extra fields and for code readability.

within the class contructor before passing back the object I have added
Code:
    # Format attributes   
    $self->{EXCLUDED_DATA} = " @{$self->{'EXCLUDED_DATA'}} ";
    $self->{NUMERIC_DATA} = " @{$self->{'NUMERIC_DATA'}} ";

Turning the arrays into static strings as the object is created, so now there is no need to dynamically do any array processing or any hash mapping against the attributes, they are converted the once as the object is instantiated and then used accordingly in my code.

Well logically it should be more efficient, but it ran so fast to start with i'm not sure I will notice much of a difference.

Thanks for the input Franco.




"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"

Google Rank Extractor -> Perl beta with FusionCharts
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top