4

次のように、キーのフラット リストをネストされたハッシュに変換する必要があります。

私の $hash = {};

my @array = qw(key1 key2 lastKey Value);

ToNestedHash($ハッシュ、@配列);

これを行います:

$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

axeman's のより良いバージョンを作ったと思います。少なくとも私には -> と \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 に答える