[Webinar] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

values in hashes

Posted on 2009-04-20
25
Medium Priority
?
190 Views
Last Modified: 2012-05-06
guys if i have a value for a hash that does not match any element in an array.. can i eliminate both the value and the key for that element?

can someone do a small example for me!??! thanks! :)
0
Comment
Question by:cucugirl
  • 12
  • 8
  • 5
25 Comments
 
LVL 39

Expert Comment

by:Adam314
ID: 24186139
You can use the delete built-in function.  Example:
use Data::Dumper;
 
my %hash;
$hash{a} = 'This is a';
$hash{b} = 'This is b';
$hash{c} = 'This is c';
 
print Dumper(\%hash);
 
delete($hash{b});
 
print Dumper(\%hash);

Open in new window

0
 
LVL 10

Expert Comment

by:oleber
ID: 24186375
you have there 2 ways, one creating a new hash, and another deleting the elements.

I optimize a litle, creating a hash from your array to fast access. you can use the grep to do the some but may be slower, much slower depending of the element number.

$array_values{$value}
can be changed to:
grep {$_ eq $value} @$array
# create a new hash 
sub clean_hash_by_copy {
    my ($hash, $array) = @_;
    my %ret_hash;
    my %array_values = map {$_=>1} @$array;
    
    while (my ($key, $value) = values %$hash) {
        $ret_hash{ $key } = $value if $array_values{$value};
    }
    return \%ret_hash;
}
 
# in the hash 
sub clean_hash {
    my ($hash, $array) = @_;
    my %array_values = map {$_=>1} @$array;
    
    foreach my $key ( keys %$hash) {
        delete($hash->{$key}) if not $array_values{$value};
    }
    return $hash;
}

Open in new window

0
 

Author Comment

by:cucugirl
ID: 24186465
question for the last solution.. what is $value going to be? in line 19?
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:cucugirl
ID: 24186566
also how would i call this subroutine?
0
 

Author Comment

by:cucugirl
ID: 24187046
when i run the second subroutine... it says $value in line 19 is not defined :'(
0
 
LVL 10

Expert Comment

by:oleber
ID: 24187248
I just cold test now.


Try the script:
use strict;
use warnings;
use Data::Dumper;
 
# create a new hash 
sub clean_hash_by_copy {
    my ($hash, $array) = @_;
    my %ret_hash;
    my %array_values = map {$_=>1} @$array;
    
    while (my ($key, $value) = each %$hash) {
        $ret_hash{ $key } = $value if $array_values{$value};
    }
    return \%ret_hash;
}
 
# in the hash 
sub clean_hash {
    my ($hash, $array) = @_;
    my %array_values = map {$_=>1} @$array;
    
    foreach my $key ( keys %$hash) {
        delete($hash->{$key}) if not $array_values{$hash->{$key}};
    }
    return $hash;
}
 
 
my %hash = (
    1=>2,
    3=>4,
    5=>6
);
 
my @array = (1..5);
 
print "1:\n";
print Dumper \%hash;
 
print "2:\n";
print Dumper clean_hash_by_copy(\%hash, \@array);
 
print "3:\n";
print Dumper \%hash;
 
print "4:\n";
clean_hash(\%hash, \@array);
print Dumper \%hash;

Open in new window

0
 

Author Comment

by:cucugirl
ID: 24187289
oleber question.. can you assing this to a hash? the return from the subroutine?
0
 
LVL 10

Expert Comment

by:oleber
ID: 24187320
like this ? ? ?

my %new_hash = %{clean_hash_by_copy(\%hash, \@array)};
0
 

Author Comment

by:cucugirl
ID: 24187359
%ghash = clean_hash(\%ihash, \@POptions);

Reference found where even-sized list expected at COPY.pl line 42. for that line... do you guys know why this error?


0
 

Author Comment

by:cucugirl
ID: 24187367
ok thanks oleber.. jus tried it like that but i have this error now.. im wondering why...
0
 
LVL 10

Expert Comment

by:oleber
ID: 24187444
use

%ghash = @{clean_hash(\%ihash, \@POptions)};

but notice that you are changing %ihash with clean_hash method.

0
 

Author Comment

by:cucugirl
ID: 24187507
oleber i get this error now: Not an ARRAY reference at COPY.pl line 44. let me show you what i got... @POptions comes from here: my @POptions = routine1();
sub routine1{
      my @values = ("gy","gx","tj","up", "12", NX");
      return @values;
}

and \%ihash comes from a file..  
0
 
LVL 39

Expert Comment

by:Adam314
ID: 24187661
It will be faster to turn the array that has the keys you want into a hash rather than search the array every time.  See this example:
#The @array is the array of keys you want to keep
my @array = qw(keyA keyC);
 
#The %hash is the hash you start with
my %hash = (keyA => 'This is A', keyB => 'This is B', keyC => 'This is C');
 
#This converts the @array to the hash %array_hash
my %array_hash;
@array_hash{@array} = ();
 
#This gets an array of the keys that exist in %hash,
#but do not exist in @array
my @keys_to_delete = grep {!exists($array_hash{$_})} keys %hash;
 
#This deletes those keys and values from %hash
foreach (@keys_to_delete) {
	delete $hash{$_};
}

Open in new window

0
 
LVL 39

Expert Comment

by:Adam314
ID: 24187679
If you want to make a copy of a hash, you don't need a complicated function, just use:
    my %new_hash = %hash;

If the %hash contains references, and you want to copy all of them, you can use the dclone function from the Storable module.
0
 

Author Comment

by:cucugirl
ID: 24187846
mm... i want to check if the values are in the array not the keys and if they are not erase both the values and the keys
0
 
LVL 10

Expert Comment

by:oleber
ID: 24187955
The idea is more to do readable simple code.

For example the line @array_hash{@array} = (); is difficult to read, even for Perl Mongers (PM Leader in here :). The line my %array_values = map {$_=>1} @$array; takes twice the time, but is more readable.

creating the @keys_to_delete is a very good wast of memory, and you are having 2 cicles.
0
 
LVL 39

Expert Comment

by:Adam314
ID: 24188183
As to difficult to read... First time I saw it, I didn't know what it did (although I had a guess).  I made a simple test script to play with that syntax, and now do not find it difficult.  If others do, and don't like it... I'd say this is even easier to read:
    $array_hash{$_}=undef foreach (@array);

>>i want to check if the values are in the array not the keys and if they are not erase both the values and the keys
I misunderstood the requirements... here is an update for this:

#The @array is the array of values you want to keep
my @array = qw(ValueA ValueC);
 
#The %hash is the hash you start with
my %hash = (keyA => 'ValueA', keyB => 'ValueB', keyC => 'ValueC');
 
#This converts the @array to the hash %array_hash
my %array_hash;
@array_hash{@array} = ();
 
#This checks each value in %hash, and deletes the key/value pair
#if the value is not in the @array
while(my ($k, $v) = each %hash) {
	next if exists($array_hash{$v});
	delete $hash{$k};
}

Open in new window

0
 
LVL 10

Expert Comment

by:oleber
ID: 24188210
the code

while(my ($k, $v) = each %hash) {
        next if exists($array_hash{$v});
        delete $hash{$k};
}

is not safe, you are changing the %hash.
0
 

Author Comment

by:cucugirl
ID: 24188269
should I copy before using this one?
0
 
LVL 10

Expert Comment

by:oleber
ID: 24188357
take your decision, my code is simple is already as a function.
if you prefer to have a new hash (as it seems) use clean_hash_by_copy subroutine

use some other code at your risk.
0
 
LVL 39

Expert Comment

by:Adam314
ID: 24188512
When saying it's not safe.... I didn't see anywhere in the question, or any of the asker's comments, that the original hash should not be changed.  The original question stated:
>>can i eliminate both the value and the key for that element

That is what my code does.  If you want to make a copy of the hash, you can use:
    my %hash2 = %hash;
Although this (and your code) would not work if %hash contains references.  In that case, you'd want to use dclose from Storable.

In this case, cucugirl... if you want to have %hash changed (meaning, have the key/value pairs removed from %hash), use the code exactly as I posted.  If you want to have a new hash, leaving the original %hash unchanged, use this code, which creates %hash2.

#The @array is the array of values you want to keep
my @array = qw(ValueA ValueC);
 
#The %hash is the hash you start with
my %hash = (keyA => 'ValueA', keyB => 'ValueB', keyC => 'ValueC');
 
#This converts the @array to the hash %array_hash
my %array_hash;
@array_hash{@array} = ();
 
#This checks each value in %hash, and creates the same key/value pair
#if the value is in the @array
while(my ($k, $v) = each %hash2) {
        next unless exists($array_hash{$v});
        $hash2{$k} = $v;
}

Open in new window

0
 

Author Comment

by:cucugirl
ID: 24188606
oleber:

sub clean_hash_by_copy {
    my ($hash, $array) = @_;
    print Dumper $hash;//PRINTS my hash
    print Dumper $array;//PRINTS my array
    my %ret_hash;
    my %array_values = map {$_=>1} @$array;
   
    print Dumper \%array_values; PRINTS THIS:

$VAR1 = {
          'N' => 1,
          'up' => 1,
          '1' => 1,
          '2' => 1,
          '3' => 1,
         
        };



    while (my ($key, $value) = each %$hash) {
        $ret_hash{ $key } = $value if $array_values{$value};
   
    }
    print Dumper \%ret_hash;
    PRINTS THIS: $VAR1 = {}; do u know what could be causing this?
    return \%ret_hash;
}
0
 

Author Comment

by:cucugirl
ID: 24188619
$VAR1 = {'N' => 1,
          'up' => 1,
          '1' => 1,
          '2' => 1,
          '3' => 1,
         
        };

i changed the value for the orginal array for other characters but that was about it... i was just wondering why the last print command will output that
0
 
LVL 10

Accepted Solution

by:
oleber earned 2000 total points
ID: 24190997
I didn't change the functions and I get the results in the Snippet


Your problems seem to be strange. Can you send me the real data? If you feel more comfortable, send your data to "oleber at gmail dot com".

use strict;
use warnings;
use Data::Dumper;
 
# create a new hash 
sub clean_hash_by_copy {
    my ($hash, $array) = @_;
    my %ret_hash;
    my %array_values = map {$_=>1} @$array;
    
    while (my ($key, $value) = each %$hash) {
        $ret_hash{ $key } = $value if $array_values{$value};
    }
    return \%ret_hash;
}
 
# in the hash 
sub clean_hash {
    my ($hash, $array) = @_;
    my %array_values = map {$_=>1} @$array;
    
    foreach my $key ( keys %$hash) {
        delete($hash->{$key}) if not $array_values{$hash->{$key}};
    }
    return $hash;
}
 
 
my %hash = (
    1=>2,
    3=>4,
    5=>'up',
    6=>'N'
);
 
my @array = (4, 'up');
 
my %new_hash = %{clean_hash_by_copy(\%hash, \@array)};
 
print "1: " . Dumper \%hash;
#1: $VAR1 = {
#          '6' => 'N',
#          '1' => 2,
#          '3' => 4,
#          '5' => 'up'
#        };
 
print "2: " . Dumper clean_hash_by_copy(\%hash, \@array);
#2: $VAR1 = {
#          '3' => 4,
#          '5' => 'up'
#        };
 
print "3: " . Dumper \%hash;
#3: $VAR1 = {
#          '6' => 'N',
#          '1' => 2,
#          '3' => 4,
#          '5' => 'up'
#        };
 
clean_hash(\%hash, \@array);
print "4:" . Dumper \%hash;
#4: $VAR1 = {
#          '3' => 4,
#          '5' => 'up'
#        };

Open in new window

0
 

Author Comment

by:cucugirl
ID: 24193329
got it to work.. .txt files where saved as PC files rather than UNIX files. Also I fixed this part of the code:

my %array_values = map {$_=>1} @$array;
    foreach (my ($key, $value) = each %$hash) {
delete($hash->{$key}) if not $array_values{$value};

that's how it should be instead to do what i wanted :)
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

I've just discovered very important differences between Windows an Unix formats in Perl,at least 5.xx.. MOST IMPORTANT: Use Unix file format while saving Your script. otherwise it will have ^M s or smth likely weird in the EOL, Then DO NOT use m…
I have been pestered over the years to produce and distribute regular data extracts, and often the request have explicitly requested the data be emailed as an Excel attachement; specifically Excel, as it appears: CSV files confuse (no Red or Green h…
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
Six Sigma Control Plans
Suggested Courses

864 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question