perl - 如何根据另一个哈希的键/值删除[子]哈希?

标签 perl hash perl-data-structures

假设我有两个哈希值。其中一个包含一组数据,只需要保留另一个哈希中显示的内容。

例如

my %hash1 = ( 
        test1 => { inner1 => { more => "alpha", evenmore => "beta" } },
        test2 => { inner2 => { more => "charlie", somethingelse => "delta" } },
        test3 => { inner9999 => { ohlookmore => "golf", somethingelse => "foxtrot" } }
    );

my %hash2 = (
        major=> { test2 => "inner2",
              test3 => "inner3" }  );

我想做的是,如果 hash1 中的整个子哈希不作为 hash2{major} 中的键/值存在,则删除它,最好没有模块。 “innerX”中包含的信息并不重要,它只是必须保留(除非要删除子哈希,然后它就会消失)。

在上面的示例中,执行此操作后,hash1 将如下所示:

my %hash1 = ( 
        test2 => { inner2 => { more => "charlie", somethingelse => "delta" } },
        );

它删除 hash1{test1} 和 hash1{test3},因为它们与 hash2 中的任何内容都不匹配。

这是我目前尝试过的方法,但它不起作用。这也可能不是最安全的做法,因为我在尝试删除哈希时循环遍历哈希。但是我正在删除每个应该没问题的吗?

这是我尝试这样做,但是 perl 提示:

当使用“严格引用”时,不能使用字符串(“inner1”)作为哈希引用

while(my ($test, $inner) = each %hash1)
{
    if(exists $hash2{major}{$test}{$inner})
    {
        print "$test($inner) is in exists.\n";
    }
    else
    {
        print "Looks like $test($inner) does not exist, REMOVING.\n";
       #not to sure if $inner is needed to remove the whole entry
         delete ($hash1{$test}{$inner});
    } 
}

最佳答案

你很接近。请记住$hash2{major}{$test}是标量,而不是哈希引用。

#! /usr/bin/perl

use strict;
use warnings;

my %hash1 = ( 
  test1 => { inner1 => { more => "alpha", evenmore => "beta" } },
  test2 => { inner2 => { more => "charlie", somethingelse => "delta" } },
  test3 => { inner9999 => { ohlookmore => "golf", somethingelse => "foxtrot" } }
);

my %hash2 = (
  major => { test2 => "inner2",
             test3 => "inner3" }
);

foreach my $k (keys %hash1) {
  my $delete = 1;
  foreach my $inner (keys %{ $hash1{$k} }) {
    $delete = 0, last if exists $hash2{major}{$k} &&
                                $hash2{major}{$k} eq $inner;
  }
  delete $hash1{$k} if $delete;
}

use Data::Dumper;
$Data::Dumper::Indent = 1;
print Dumper \%hash1;

$delete = 0, ... 开头的行有点可爱。相当于$delete = 0; last;在另一个条件中,但它已经嵌套了两次。不想建立一个 matryoshka doll ,我用了statement modifier ,但顾名思义,它修改单个语句。

那就是Perl's comma operator进来:

Binary , is the comma operator. In scalar context it evaluates its left argument, throws that value away, then evaluates its right argument and returns that value. This is just like C's comma operator.

在本例中,左侧参数是表达式 $delete = 0 ,正确的参数是 last .

条件可能看起来不必要的挑剔,但是

... if $hash2{major}{$k} eq $inner;

当探测 %hash2 中未提及的测试时,会产生未定义值警告(例如,test1/inner1)。使用

.. if $hash2{major}{$k} && $hash2{major}{$k} eq $inner;

会错误地删除 %hash2 中提到的测试如果它的“内部名称”是一个假值,例如字符串 "0" 。是的,使用 exists这里可能不必要地挑剔,但由于不知道你的实际哈希键,我选择了保守的路线。

输出:

$VAR1 = {
  'test2' => {
    'inner2' => {
      'somethingelse' => 'delta',
      'more' => 'charlie'
    }
  }
};

Although you don't violate it, be aware of the following caveat related to using each:

If you add or delete elements of a hash while you're iterating over it, you may get entries skipped or duplicated, so don't. Exception: It is always safe to delete the item most recently returned by each, which means that the following code will work:

    while (($key, $value) = each %hash) {
      print $key, "\n";
      delete $hash{$key};   # This is safe
    }

Update: Searching hashes as though they were arrays (impress your CS nerd friends by saying “… linearly rather than logarithmically”) is a red flag, and the code above does just that. A better approach, which turns out to be similar to Penfold's answer, is

%hash1 = map +($_ => $hash1{$_}),
         grep exists $hash2{major}{$_} &&
              exists $hash1{$_}{ $hash2{major}{$_} },
         keys %hash1;

它以漂亮的声明式风格描述了 %hash1 所需的内容,即

  1. 一级 key %hash1应该在 $hash2{major} 中提到,并且
  2. $hash2{major} 中的值对应于每个一级 key 本身应该是 %hash1 中该 key 的子 key

(哇,令人眼花缭乱。我们需要多个英文占位符变量!)

+($_ => $hash1{$_}) 中的一元加号为较差的解析器消除歧义,因此它知道我们希望将表达式视为“对”。见文末perlfunc documentation on map 对于其他可能需要这样做的情况。

关于perl - 如何根据另一个哈希的键/值删除[子]哈希?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2569079/

相关文章:

Perl 模块加载 - 防止 : perhaps you forgot to load "Bla"?

ruby-on-rails - Ruby on Rails : Submitting an array in a form

perl - 如何在 Perl 哈希表中存储多个值?

perl - 如何删除重复值并创建新的 perl 哈希?

perl - 有没有办法用更好的东西替换Perl中的if-elsif-else?

perl - LWP::UserAgent 不是线程安全的吗?

multithreading - Perl 线程 : share GLOB between threads

linux - 用于查找无主文件的 Perl 脚本未找到任何内容

javascript - 如何用另一个响应替换窗口的 URL 哈希值?

javascript - 如何使用 crypto 检查字符串是否已在 Node.js 中进行哈希处理