4

我需要将一个平面键列表转换为嵌套哈希,如下所示:

我的 $hash = {};

我的@array = qw(key1 key2 lastKey Value);

ToNestedHash($hash, @array);

会这样做:

$hash{'key1'}{'key2'}{'lastKey'} = "值";

4

4 回答 4

12
sub to_nested_hash {
    my $ref   = \shift;  
    my $h     = $$ref;
    my $value = pop;
    $ref      = \$$ref->{ $_ } foreach @_;
    $$ref     = $value;
    return $h;
}

解释:

  • 取第一个值作为 hashref
  • 取最后一个值作为要赋值的值
  • 其余的是钥匙。
  • 然后创建对基本哈希的SCALAR引用。
  • 反复:
    • 取消引用指针以获取哈希(第一次)或将指针自动激活为哈希
    • 获取密钥的哈希槽
    • 并将标量引用分配给哈希槽。
    • (下次这将自动激活到指定的哈希)。
  • 最后,参考最里面的槽,赋值。

我们知道:

  • 哈希或数组的占用者只能是标量或引用。
  • 引用是一种标量。( my $h = {}; my $a = [];)。
  • 因此, \$h->{ $key } 是对堆上标量槽的引用,可能是自动激活的。
  • 如果我们这样处理嵌套哈希的“级别”,则可以将其自动激活为哈希引用。

这样做可能更明确:

foreach my $key ( @_ ) { 
    my $lvl = $$ref = {};
    $ref    = \$lvl->{ $key };
}

但由于重复使用这些参考成语,我完全按原样写了那行,并在发布前对其进行了测试,没有错误。

至于替代方案,以下版本“更容易”(想出)

sub to_nested_hash {
    $_[0] //= {};
    my $h     = shift;
    my $value = pop;
    eval '$h'.(join '', map "->{\$_[$i]}", 0..$#_).' = $value';
    return $h;
}

但慢了大约 6-7 倍。

于 2012-07-16T13:36:07.873 回答
1

我认为这段代码更好 - 更适合移动到类方法中,并且可以根据提供的参数设置一个值。否则选择的答案很整洁。

#!/usr/bin/env perl

use strict;
use warnings;
use YAML;

my $hash = {};

my @array = qw(key1 key2 lastKey);
my $val = [qw/some arbitrary data/];

print Dump to_nested_hash($hash, \@array, $val);
print Dump to_nested_hash($hash, \@array);
sub to_nested_hash {
    my ($hash, $array, $val) = @_;
    my $ref   = \$hash;
    my @path = @$array;
    print "ref: $ref\n";
    my $h     = $$ref;
    $ref      = \$$ref->{ $_ } foreach @path;
    $$ref     = $val if $val;
    return $h;
}
于 2014-02-01T02:44:28.833 回答
0

谢谢你的好东西!!!

我用递归的方式做到了:

sub Hash2Array
{
  my $this = shift;
  my $hash = shift;

  my @array;
  foreach my $k(sort keys %$hash)
  {
    my $v = $hash->{$k};
    push @array,
      ref $v eq "HASH" ? $this->Hash2Array($v, @_, $k) : [ @_, $k, $v ];
  }

  return @array;
}

在所有这些解决方案之间进行性能比较会很有趣......

于 2012-07-27T07:07:11.757 回答
0

我认为制作了一个更好的斧头版本。至少没有 -> 和 \shift 对我来说更容易理解。3 行没有子程序。

带子程序

sub to_nested_hash {
    my $h=shift;
    my($ref,$value)=(\$h,pop);
    $ref=\%{$$ref}{$_} foreach(@_);
    $$ref=$value;
    return $h;
}

my $z={};
to_nested_hash($z,1,2,3,'testing123');

无子程序

my $z={};

my $ref=\$z; #scalar reference of a variable which contains a hash reference
$ref=\%{$$ref}{$_} foreach(1,2,3); #keys
$$ref='testing123'; #value

#with %z hash variable just do double backslash to get the scalar reference
#my $ref=\\%z;

结果:

$VAR1 = {
          '1' => {
                   '2' => {
                            '3' => 'testing123'
                          }
                 }
        };
于 2019-09-10T16:48:52.640 回答