问题
I have a hash of complex structure and I want to perform a search and replace. The first hash is like the following:
$VAR1 = {
abc => { 123 => ["xx", "yy", "zy"], 456 => ["ab", "cd", "ef"] },
def => { 659 => ["wx", "yg", "kl"], 456 => ["as", "sd", "df"] },
mno => { 987 => ["lk", "dm", "sd"] },
}
and I want to iteratively search for all '123'/'456' elements, and if a match is found, I need to do a comparison of the sublayer, i.e. of ['ab','cd','ef']
and ['as','sd','df']
and in this case, keep only the one with ['ab','cd','ef']. So the output will be as follows:
$VAR1 = {
abc => { 123 => ["xx", "yy", "zy"], 456 => ["ab", "cd", "ef"] },
def => { 659 => ["wx", "yg", "kl"] },
mno => { 987 => ["lk", "dm", "sd"] },
}
So the deletion is based on the substructure, and not index. How can it be done? Thanks for the help!!
Lets assume that I will declare the values to be kept, i.e. I will keep 456 => ["ab", "cd", "ef"] based on a pre-declared value of ["ab", "cd", "ef"] and delete any other instance of 456 anywhere else. The search has to be for every key. so the code will go through the hash, first taking 123 => ["xx", "yy", "zy"] and compare it against the keys throughout the rest of the hash, if no match is found, do nothing. If a match is found, like in the case of 456 => ["ab", "cd", "ef"], it will compare the two, and as I have said that in case of a match the one with ["ab", "cd", "ef"] would be kept, it will keep 456 => ["ab", "cd", "ef"] and discard any other instances of 456 anywhere else in the hash, i.e. it will delete 456 => ["as", "sd", "df"] in this case.
回答1:
Here is a solution that uses the smart match operator to perform the array comparison:
Update: as Borodin pointed out, my original code was wrong. This is the fixed version.
Update 2: Changed it to choose the values to keep based on a hash structure.
my $VAR1 = {
abc => { 123 => ["xx", "yy", "zy"], 456 => ["ab", "cd", "ef"] },
def => { 659 => ["wx", "yg", "kl"], 456 => ["as", "sd", "df"] },
mno => { 987 => ["lk", "dm", "sd"] },
};
my %keep_values = (
'456' => ['ab','cd','ef']
);
foreach my $outer_key (keys %$VAR1)
{
foreach my $keepers (keys %keep_values)
{
if (exists $VAR1->{$outer_key}{$keepers} and
#use the smart match operator to compare arrays.
!(@{$VAR1->{$outer_key}{$keepers}} ~~ @{$keep_values{$keepers}}))
{
delete $VAR1->{$outer_key}{$keepers};
}
}
}
For more on the smart match operator, see perlop.
来源:https://stackoverflow.com/questions/12674418/compare-and-edit-underlying-structure-in-hash