Perl哈希表中嵌套哈希表的解引用

3

我正在学习Perl。

我正在尝试使用临时变量重写此多级循环,以便我不需要先获得前面的键 ($key1 $key2) 才能访问(解引用) $key3。最简单的方法是什么?谢谢。

for my $key1 ( keys %foo )
{
    for my $key2 ( keys %{$foo{$key1}} )
    {
        for my $key3 ( keys %{$foo{$key1}{$key2}} )

如果你的数据结构变得太复杂,你可以考虑使用面向对象编程(OOP)。 - ThisSuitIsBlackNot
1
如果你正在学习Perl和数据结构,必读的内容包括 Perl References TutorialPerl Data Structures Cookbook。它讨论了你的问题和其他事项。关于数组中的数组,请查看一个有趣命名为 perllol (Perl Lists of Lists)。 - Dan Dascalescu
4个回答

5
您可以这样使用whileeach
while (my ($key1, $inner_hash) = each %foo) {

    while (my ($key2, $inner_inner_hash) = each %$inner_hash) {

        while (my ($key3, $value) = each %$inner_inner_hash) {
            print $value;
        }
    }
}

这种方法比foreach keys %hash占用的内存更少,因为它在开始迭代之前不会构建哈希中所有键的列表。但是,each的缺点是无法指定排序顺序。有关详细信息,请参阅文档

我不清楚你所说的“each”比“for”使用更少的内存是什么意思。两者都是迭代器,但是除非将其应用于哈希的“keys”或“values”,否则“for”在哈希上并不真正有用,此时它们之间几乎没有区别。 - Borodin
啊,你是在想 for (keys %hash) { ... } 首先会从哈希表的键中生成一个新数组吗?我之前没有考虑过这个问题,但这似乎不太可能。我要进行实验。 - Borodin
@Borodin 是的,我应该更清楚。keys %hash 在你开始迭代之前生成所有键的列表;而 each %hash 则不会。 - ThisSuitIsBlackNot

4
您正在寻找类似于此的内容:
for my $key1 ( keys %foo )
{
    my $subhash = $foo{$key1};
    for my $key2 ( keys %$subhash )
    {
        my $subsubhash = $subhash->{$key2};
        for my $key3 ( keys %$subsubhash )

2
这个怎么样?
foreach(values %foo){
  foreach(values %$_){
    foreach my $key3 (keys %$_){
      print $key3;
    }
  }
}

1

我正在学习perl。

而你已经在使用引用了,做得很好。

我正在尝试使用临时变量重写这个多层循环,以便不需要先获取前两个键($key1 $key2)来访问(解引用)$key3。如何最简单地实现呢?

如果我理解正确的话,你想要能够查找所有第三层哈希键而无需遍历所有第一层和第二层哈希键。

假设 %foo 有以下键:

$foo{one}->{alpha}->{apple};
$foo{one}->{alpha}->{berry};
$foo{one}->{beta}->{cucumber};
$foo{one}->{beta}->{durian};
$foo{two}->{uno}->{eggplant};
$foo{two}->{uno}->{fig};
$foo{two}->{dos}->{guava};
$foo{two}->{dos}->{honeydew};

顺便说一句,我喜欢->语法,因为它提醒我正在处理对某个东西的引用而不是一个实际的哈希。它帮助我更清晰地看到问题。
你想遍历蔬菜和水果名称的键,而不经过前两个层级。是这样的吗?
在这里,->语法有助于澄清答案。这八个键属于四个不同的哈希:
$foo{one}->{alpha};
$foo{one}->{beta};
$foo{two}->{uno};
$foo{two}->{dos};

而且,它们所在的哈希是匿名的,也就是说没有包含这些哈希的变量名。我访问这些哈希的唯一方法是找到包含它们的四个哈希。

然而,这四个键本身存储在两个单独的哈希中。我需要找到这两个哈希以找到它们的键。同样,这两个哈希也是匿名的。同样,我唯一能找到它们的方法是知道包含它们的两个哈希:

$foo{one};
$foo{two};

因此,为了找到我的第三级值,我需要知道包含它们的第二级哈希。为了找到这些第二个哈希,我需要找到包含它们的第一级键。
然而,如果您有某种已知结构,则可能已经知道您需要查找所需值的键。
想象一下像这样的东西:
$person{$ssn}->{NAME}->{FIRST} = "Bob";
$person{$ssn}->{NAME}->{MI}    = "Q.";
$person{$ssn}->{NAME}->{LAST}  = "Smith";

在这里,我可以直接访问每个人的名字的第一个、最后一个和中间字母。我所需要做的就是通过各种社会保障号码进行搜索:

for my $ssn ( sort keys %person ) {
    say "My name is " . $person{$ssn}->{NAME}->{FIRST}
       . " " . $person{$ssn}->{NAME}->{MI}
       . " " . $person{$ssn}->{NAME}->{LAST};
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接