Reputation: 95
I have an array of key names and need to remove any keys that are not in this list from a hash.
I gather deleting keys in a hash is a Bad Thing while iterating over it, but it does seem to work:
use strict;
use warnings;
use Data::Dumper;
my @array=('item1', 'item3');
my %hash=(item1 => 'test 1', item2 => 'test 2', items3 => 'test 3', item4 => 'test 4');
print(Dumper(\%hash));
foreach (keys %hash)
{
delete $hash{$_} unless $_ ~~ @array;
}
print(Dumper(\%hash));
gives the output:
$VAR1 = {
'item3' => 'test 3',
'item1' => 'test 1',
'item2' => 'test 2',
'item4' => 'test 4'
};
$VAR1 = {
'item3' => 'test 3',
'item1' => 'test 1'
};
What is a better/cleaner/safer way of doing this?
Upvotes: 2
Views: 797
Reputation: 57650
Don't use smartmatch ~~
, it's fundamentally broken and will likely be removed or substantially changed in upcoming releases of Perl.
The easiest solution is to build a new hash only containing those elements you're interested in:
my %old_hash = (
item1 => 'test 1',
item2 => 'test 2',
item3 => 'test 3',
item4 => 'test 4',
);
my @keys = qw/item1 item3/;
my %new_hash;
@new_hash{@keys} = @old_hash{@keys}; # this uses a "hash slice"
If you want to update the original hash, then do %old_hash = %new_hash
afterwards. If you don't want to use another hash, you might like to use List::MoreUtils qw/zip/
:
# Unfortunately, "zip" uses an idiotic "prototype", which we override
# by calling it like "&zip(...)"
%hash = &zip(\@keys, [@hash{@keys}]);
which has the same effect.
Upvotes: 3