【问题标题】:Accessing a multi-dimensional hash using strings使用字符串访问多维哈希
【发布时间】:2019-02-26 23:33:35
【问题描述】:

我有一个大型多维散列,它是 JSON 结构的导入。

my %bighash;

%bighash 中有一个元素叫做:

$bighash{'core'}{'dates'}{'year'} = 2019.

我有一个名为 core.dates.year 的单独字符串变量,我想用它从 %bighash 中提取 2019。

我已经写了这段代码:

my @keys  = split(/\./, 'core.dates.year');
my %hash = ();
my $hash_ref = \%hash;

for my $key ( @keys ){
    $hash_ref->{$key} = {};
    $hash_ref = $hash_ref->{$key};
}

当我执行时:

say Dumper \%hash;

输出:

$VAR1 = {
          'core' => {
                   'dates' => {
                             'year' => {}
                           }
                 }
        };

到目前为止一切顺利。但我现在想做的是:

print $bighash{\%hash};

我想返回 2019。但是没有返回任何内容,或者我看到有关“在连接 (.) 或 script.pl 第 1371 行第 17 行的字符串中使用未初始化值的错误(#1 )...

有人能告诉我发生了什么吗?

我的项目涉及将字符串嵌入到外部文件中,然后将其替换为 %bighash 中的实际值,因此它只是字符串插值。

谢谢!

【问题讨论】:

  • 我在回答中加入了更快、更简单的 Data::Diver 的 DiveDiveVal 版本。

标签: perl hash


【解决方案1】:

有人能告诉我发生了什么[当我使用$bighash{\%hash}时]?

哈希键是字符串,\%hash 的字符串化类似于HASH(0x655178)%bighash 中唯一的元素以 core(而不是 HASH(0x655178))作为键,因此哈希查找返回 undef


有用的工具:

sub dive_val :lvalue { my $p = \shift; $p //= \( $$p->{$_} ) for @_; $$p }   # For setting
sub dive { my $r = shift; $r //= $r->{$_} for @_; $r }                       # For getting

dive_val(\%hash, split /\./, 'core.dates.year') = 2019;
say dive(\%hash, split /\./, 'core.dates.year');

【讨论】:

  • %bighash 有一个条目:$bighash{'core'}{'dates'}{'year'} = 2019。这就是我要访问的内容。它是多维的。
  • 如果我打印 $bighash{'core'}{'dates'}{'year'} 那么我会得到 2019 作为答案。我想做的是说 print $bighash{\%hash} 得到相同的答案。
  • 可能是这样,但$bighash{\%hash} 有其他含义。你的问题是“有人能告诉我发生了什么吗?”$bighash{\%hash}
  • 您可能想对这些潜水艇做一些解释。尤其是lvalue 相当先进。
  • @simbabque,我已经在我的回答中记录了如何使用它们。相反,如果您对它的工作原理感兴趣,可以查看here 的解释。
【解决方案2】:

Hash::Fold 在这里似乎很有帮助。您可以“展平”您的哈希,然后使用单个密钥访问所有内容。

use Hash::Fold 'flatten';
my $flathash = flatten(\%bighash, delimiter => '.');
print $flathash->{"core.dates.year"};

【讨论】:

    【解决方案3】:

    Perl 中没有多维散列。哈希是键/值对。您对 Perl 数据结构的理解不完整。

    重新想象你的数据结构如下

    my %bighash = (
        core => {
            dates => {
                year => 2019,
            },
        },
    );
    

    圆括号() 和花括号{} 之间存在差异。变量名上的% sigil 表示它是一个散列,即一组无序的键/值对。一轮() 是一个列表。该列表中有两个标量值,即一个键和一个值。该值是对另一个匿名哈希的引用。这就是为什么它有卷曲的{}

    每个级别都是一个单独的、不同的数据结构。

    您的代码重写类似于 ikegami wrote in his answer,但效率较低且更冗长。

    my @keys = split( /\./, 'core.dates.year' );
    
    my $value = \%bighash;
    for my $key (@keys) {
      $value //= $value->{$key};
    }
    
    print $value;
    

    它一步一步深入到结构中,最终给你最终的价值。

    【讨论】:

    • 所以这对我有用。我还尝试了 ikegami 提供的潜水选项,但潜水只返回哈希 HASH(0x7fe01084fec8) 而不是值 2019。所以我认为你的解决方案是我应该采用的解决方案。我还需要阅读有关哈希和数据结构的更多信息。
    • Re "所以这对我有用。",答案说,它和我的一样。 (不过我修复了dive_val 中的一个错误)
    • @ikegami 你知道我不是想偷你的答案,对吧? :)
    • @simbabque,我对你的回答完全没有问题。我只是在反驳马里奥的说法。
    猜你喜欢
    • 2021-12-10
    • 1970-01-01
    • 2011-10-31
    • 2012-02-19
    • 2012-04-25
    • 2015-06-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多