cucugirl
asked on
values in hashes
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! :)
can someone do a small example for me!??! thanks! :)
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
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;
}
ASKER
question for the last solution.. what is $value going to be? in line 19?
ASKER
also how would i call this subroutine?
ASKER
when i run the second subroutine... it says $value in line 19 is not defined :'(
I just cold test now.
Try the script:
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;
ASKER
oleber question.. can you assing this to a hash? the return from the subroutine?
like this ? ? ?
my %new_hash = %{clean_hash_by_copy(\%has h, \@array)};
my %new_hash = %{clean_hash_by_copy(\%has
ASKER
%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?
Reference found where even-sized list expected at COPY.pl line 42. for that line... do you guys know why this error?
ASKER
ok thanks oleber.. jus tried it like that but i have this error now.. im wondering why...
use
%ghash = @{clean_hash(\%ihash, \@POptions)};
but notice that you are changing %ihash with clean_hash method.
%ghash = @{clean_hash(\%ihash, \@POptions)};
but notice that you are changing %ihash with clean_hash method.
ASKER
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..
sub routine1{
my @values = ("gy","gx","tj","up", "12", NX");
return @values;
}
and \%ihash comes from a file..
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{$_};
}
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.
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.
ASKER
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
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.
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.
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:
$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};
}
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.
while(my ($k, $v) = each %hash) {
next if exists($array_hash{$v});
delete $hash{$k};
}
is not safe, you are changing the %hash.
ASKER
should I copy before using this one?
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.
if you prefer to have a new hash (as it seems) use clean_hash_by_copy subroutine
use some other code at your risk.
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.
>>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;
}
ASKER
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;
}
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;
}
ASKER
$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
'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
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
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 :)
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 :)
Open in new window