Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Perl 如何创建哈希的递归哈希?(无限深)_Perl_Data Structures - Fatal编程技术网

Perl 如何创建哈希的递归哈希?(无限深)

Perl 如何创建哈希的递归哈希?(无限深),perl,data-structures,Perl,Data Structures,请,我尝试创建一个复杂的数据结构。我知道怎么做 $branch{'level1'}{'level2'}{'level3'}='leaf'; 但我不知道如何创造 $branch{'level1'}....{'levelN'}='leaf'; 我试着这样做: $branch{'leaf'} = "1"; $branchREF = \%branch; $branchtmp{'level3'} = $branchREF; 因此,我成功地得到: $VAR1 = 'level3'; $VAR2 = {

请,我尝试创建一个复杂的数据结构。我知道怎么做

$branch{'level1'}{'level2'}{'level3'}='leaf';
但我不知道如何创造

$branch{'level1'}....{'levelN'}='leaf';
我试着这样做:

$branch{'leaf'} = "1";
$branchREF = \%branch;
$branchtmp{'level3'} = $branchREF;
因此,我成功地得到:

$VAR1 = 'level3';
$VAR2 = {
          'leaf' => '1'
        };
但对于下一步,要对哈希进行重新创建的N哈希,我尝试:

%branch = %branchtmp;
但结果是完全错误的<代码>%branch不是我所期望的。为了实现递归性,我需要重用我的第一个
%分支
,而不是创建一个新分支。请问我该怎么办

A.

可以帮助您:

#!/usr/bin/perl
use warnings;
use strict;

use Data::Diver qw{ DiveVal };
use Data::Dumper;

my %branch;
DiveVal(\%branch, map "level$_", 1 .. 3) = 'leave';
print Dumper \%branch;
输出:

$VAR1 = {
          'level1' => {
                        'level2' => {
                                      'level3' => 'leave'
                                    }
                      }
        };
$VAR1 = {
          'level1' => {
                        'level2' => {
                                      'level3' => 'leaf'
                                    }
                      }
        };
$VAR1 = {
          'level1' => {
                        'level2' => {
                                      'level3' => 'leaf'
                                    }
                      }
        };
或者,如果您想自己实施:

#!/usr/bin/perl
use warnings;
use strict;

use Data::Dumper;

sub set_value {
    my ($struct, @list) = @_;
    if (@list > 2) {
        set_value($struct->{ $list[0] } = {}, @list[ 1 .. $#list ]);
    } else {
        $struct->{ $list[0] } = $list[1];
    }
}


my %branch;
set_value(\%branch, map("level$_", 1 .. 3), 'leave');
print Dumper \%branch;

最简单的方法是记住perl如何处理多维数据结构。它是通过引用来实现的。因此,您可能会发现从顶层开始更简单,而是作为散列引用:

#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;

my @levels = qw ( level1 level2 level3 );

my $branch = {};

my $tail = pop(@levels);
my $cursor = $branch;
#iterate our levels
foreach my $level (@levels) { 
   #make a new anon-hash if there isn't one. 
   $cursor -> {$level} ||= {};
   #traverse down
   $cursor = $cursor->{$level};
}
#set a value
$cursor -> {$tail} = 'leaf';

print Dumper $branch;
输出:

$VAR1 = {
          'level1' => {
                        'level2' => {
                                      'level3' => 'leave'
                                    }
                      }
        };
$VAR1 = {
          'level1' => {
                        'level2' => {
                                      'level3' => 'leaf'
                                    }
                      }
        };
$VAR1 = {
          'level1' => {
                        'level2' => {
                                      'level3' => 'leaf'
                                    }
                      }
        };

注意-为了再次执行此操作,您必须重置光标并“重新遍历”,但可以以类似的方式“遍历”结构

一个简单的递归解决方案:

#!/usr/bin/env perl   
use strict;
use warnings;
use Data::Dumper;

sub recursiveHash {
    my ($result, @rest) = @_;
    return $result unless @rest;

    my $nextTag = pop @rest;
    return recursiveHash( {$nextTag => $result}, @rest);
}

print Dumper(recursiveHash('leaf', 'level1', 'level2', 'level3'));
输出:

$VAR1 = {
          'level1' => {
                        'level2' => {
                                      'level3' => 'leave'
                                    }
                      }
        };
$VAR1 = {
          'level1' => {
                        'level2' => {
                                      'level3' => 'leaf'
                                    }
                      }
        };
$VAR1 = {
          'level1' => {
                        'level2' => {
                                      'level3' => 'leaf'
                                    }
                      }
        };
也就是说,Perl中的子例程调用相当慢。幸运的是,这里完全不需要递归

sub iterativeHash {
    my ($result, @rest) = @_;
    while (@rest) {
       my $nextTag = pop @rest;
       $result = { $nextTag => $result };
    }
    return $result;
}

我强烈建议使用现有的解决方案,例如


显然,它也可以在没有模块的情况下完成

sub DiveVal :lvalue {
   my $p = \shift;
   $p = \( $$p->{$_} ) for @_;
   $$p
}

my @keys = map "level$_", 1 .. 3;

my $branch;
DiveVal($branch, @keys) = 'leaf';
  -or-
my %branch;
DiveVal(\%branch, @keys) = 'leaf';

my
DiveVal
的工作原理:

Pre-loop:$p引用$branch
循环传递0之后:$p引用$branch->{level1}
在循环过程1之后:$p引用$branch->{level1}{level2}
循环传递2之后:$p引用$branch->{level1}{level2}{level3}
返回:$branch->{level1}{level2}{level3}
额外的间接层次有很多好处

  • 它消除了对最后一个键进行特殊处理的需要
  • 它消除了在取消引用散列之前创建散列的需要
  • 它消除了根作为散列引用的需要。相反,任何标量都可以是根,甚至是未定义的根
  • 它使扩展
    DiveVal
    以支持混合数组/散列结构变得容易

我使用DBM::Deep,您可能需要自己安装它。我需要能够处理长键值和大约100000个键的东西。普通的Perl散列(默认安装的散列)只处理1008字节的组合键和数据长度



我对每个人的回答速度印象深刻!我真的很喜欢你回答这个问题的方式:我不需要额外的模块,而且我发现递归的方式非常简单。所以我得到了你的答案,但是Sobrique和Choroba的答案也很好。谢谢!:)不幸的是,这种方法不能用于添加到现有结构中,如
DiveVal($root,@keys)=$leaf可以。谢谢你,乔洛巴。我倾向于第二种方法,不需要额外的模块,但我觉得eballes方法更简单一点。谢谢你的回答!:)@choroba,你可能有兴趣看看。如果你同时替换
$cursor=
$cursor=\(…)
并调整
$cursor
的所有其他实例。谢谢你的回答,我从中学到了很多。我只想链接到。我需要它:)@ikegami,如果你是Data::Diver的作者,我已经通过CPAN向你发送了一封电子邮件,即发送到你的CPAN.org电子邮件地址。我不确定该电子邮件是否会转发到您的真实电子邮件地址。@Bulrush,我不维护该模块。我的CPAN名称与我的SO名称相同。是的,CPAN地址是邮件转发器。