Perl哈希的哈希的哈希的哈希。。。是否有';简单';在列表末尾获取元素的方法?

Perl哈希的哈希的哈希的哈希。。。是否有';简单';在列表末尾获取元素的方法?,perl,hash-of-hashes,Perl,Hash Of Hashes,我有一个Perl散列的散列。。。大约11或12个元素深。请原谅我没有重复下面的结构 一些级别有固定的标签,例如,'NAMES','AGES'或类似的,因此访问这些级别是可以的,因为我可以直接使用标签,但我需要循环其他变量,这会导致一些非常长的语句。这是一组循环的一半的示例: foreach my $person (sort keys %$people) { foreach my $name (sort keys %{$people->{$person}{'NAMES'}})

我有一个Perl散列的散列。。。大约11或12个元素深。请原谅我没有重复下面的结构

一些级别有固定的标签,例如,
'NAMES'
'AGES'
或类似的,因此访问这些级别是可以的,因为我可以直接使用标签,但我需要循环其他变量,这会导致一些非常长的语句。这是一组循环的一半的示例:

foreach my $person (sort keys %$people) {
        foreach my $name (sort keys %{$people->{$person}{'NAMES'}}) {
            foreach my $age (sort keys %{$people->{$person}{'NAMES'}{$name}{'AGES'}}) {
                . . . # and so on until I get to the push @list,$element; part
这只是一个例子,但它遵循了我的结构。没有固定名称部分(大写元素)可能会更短,但在其他地方,它们是引用所必需的

我尝试将元素转换为散列,以在每个阶段缩短它, e、 g.在第二个论坛上,我尝试了各种形式的:

foreach my $name (sort keys %{$person->{'NAMES'}})
但这不起作用。我肯定我以前见过类似的东西,所以语义可能不正确

我研究过关于散列的页面,以及对散列及其元素的引用等等。我见过
的例子,虽然每个
都循环,但它们似乎并不是特别短或更容易实现。也许只是有一种不同的方法来做这件事,我没有抓住要点。我已经写了一次完整的
foreach
循环集,如果我不必再重复六次左右,那就太好了


当然,可能没有“简单”的方法,但是感谢所有的帮助

$person
是关键,要缩短内部循环的时间,您需要将值分配给某些内容:

foreach my $person_key (sort keys %$people) {
    my $person = $people->{$person_key};
    my $names  = $person->{NAMES};
    foreach my $name (sort keys %$names) {

您还可以使用每个关键字。这肯定会有所帮助

while( my ($person, $val1) = each(%$people) ) {
    while( my ($name, $val2) = each(%$val1) ) {
        while( my ($age, $val3) = each(%$val2) ) {
            print $val3->{Somekey};

如果希望构建更灵活的解决方案,可以递归地遍历数据树。考虑这个示例数据树(任意深度):

示例数据 根据你的问题,我得出结论,你只想在树叶上工作(
AGE
s)。因此,我们可以编写一个递归的
遍历
子例程,在它可能找到的所有叶子上执行一个给定的subref,其顺序为键排序深度优先。为了方便起见,此子引用获取leave本身和散列键路径:

准备工作 我认为从内联评论来看,这家伙是如何工作的,这一点很清楚。如果您愿意的话,在所有节点上执行coderef并不是什么大的改变,而不仅仅是在叶子上。请注意,为了方便起见,我特意在这里添加了一个原型,因为它非常容易使用
travel
和众所周知的
map
grep
语法:

在数据上执行内容 还要注意的是,它对散列引用有效,我们使用隐式空列表初始化了
@path

输出

42 (bladepanthera NAMES blade AGE)
17 (bladepanthera NAMES panthera AGE)
666 (memowe NAMES memo AGE)
667 (memowe NAMES we AGE)
给定的子例程(作为
{block}
编写)可以对给定的数据执行任何操作。例如,此更可读的推送子例程:

my @flattened_people = ();

traverse {
    my ($thing, @path) = @_;
    push @flattened_people, { age => $thing, path => \@path };
} \%people;

您可以使用,这是一种文件::查找数据结构。

听起来您的代码将受益于不同的数据模型。我很难想象与11或12级哈希对应的真实情况。例如,即使一个人有多个名字,他们肯定不应该有多个年龄?因此,
AGE
应该只是person级别的另一个散列键。也许使用Perl的面向对象功能会有所帮助:@WinnieNicklaus,XML通常有12层的节点。这只是一个示例数据集,它实际上与人没有关联,但我使用它只是为了显示代码的结构。数据对应于数据库的一部分,并引用了一组ID,这些ID在早期阶段会得到更好的缩减,否则会导致程序稍后的速度减慢。它冗长乏味,但适用于它所代表的内容:)这使得不可能找到合适的变量名。你能给出一些有意义的东西吗?国家->县->城市->街道->房子->人(姓名,年龄)啊,这是个好主意!我可以做
$names=$people->{$person\u key}{names}
traverse { say shift . " (@_)" } \%people;
42 (bladepanthera NAMES blade AGE)
17 (bladepanthera NAMES panthera AGE)
666 (memowe NAMES memo AGE)
667 (memowe NAMES we AGE)
my @flattened_people = ();

traverse {
    my ($thing, @path) = @_;
    push @flattened_people, { age => $thing, path => \@path };
} \%people;