如何在Perl中迭代散列?
我有一个散列,其中键的值是其他散列 示例:如何在Perl中迭代散列?,perl,hash,perl-data-structures,Perl,Hash,Perl Data Structures,我有一个散列,其中键的值是其他散列 示例:{'key'=>{'key2'=>{'key3'=>'value'}} 如何遍历此结构?您必须循环遍历它两次。i、 e foreach my $keyname (keys(%foo) { my $subhash = $foo{$keyname}; # stuff with $subhash as the value at $keyname } while ( ($family, $roles) = each %HoH ) { print
{'key'=>{'key2'=>{'key3'=>'value'}}
如何遍历此结构?您必须循环遍历它两次。i、 e
foreach my $keyname (keys(%foo) {
my $subhash = $foo{$keyname};
# stuff with $subhash as the value at $keyname
}
while ( ($family, $roles) = each %HoH ) {
print "$family: ";
while ( ($role, $person) = each %$roles ) {
print "$role=$person ";
}
print "\n";
}
另外,请通读一遍。您可以深入了解散列可能有用
foreach my $key (keys %hash) {
foreach my $key2 (keys %{ $hash{$key} }) {
foreach my $key3 (keys %{ $hash{$key}{$key2} }) {
$value = $hash{$key}{$key2}->{$key3};
# .
# .
# Do something with $value
# .
# .
# .
}
}
}
这是你想要的吗?(未经测试)
这个答案建立在Dave Hinton的想法基础上,即编写一个通用子例程来遍历散列结构。这样的散列遍历器接受一个代码引用,并简单地为散列中的每个叶节点调用该代码 使用这种方法,可以使用同一个hash walker做很多事情,具体取决于我们给出的回调。为了获得更大的灵活性,您需要传递两个回调——一个在值为哈希引用时调用,另一个在值为普通标量值时调用。马克·杰森·多米努斯(Marc Jason Dominus)的优秀著作更深入地探讨了这类策略
前面的答案展示了如何推出您自己的解决方案,最好至少做一次,以便您了解perl引用和数据结构的工作原理。你一定要通读一遍,如果你还没有通读的话
但是,您不需要编写自己的解决方案——CPAN上已经有一个模块可以为您迭代任意复杂的数据结构:。这并不是一个新的答案,但我想分享如何做更多 只需递归打印所有哈希值,还可以根据需要修改它们 下面是我对dave4420的答案所做的微小修改,其中 该值作为引用传递给回调,因此我的回调 然后,例程可以修改散列中的每个值 当每个循环创建副本时,我还必须重建散列 不是参考资料
sub hash_walk {
my $self = shift;
my ($hash, $key_list, $callback) = @_;
while (my ($k, $v) = each %$hash) {
# Keep track of the hierarchy of keys, in case
# our callback needs it.
push @$key_list, $k;
if (ref($v) eq 'HASH') {
# Recurse.
$self->hash_walk($v, $key_list, $callback);
}
else {
# Otherwise, invoke our callback, passing it
# the current key and value, along with the
# full parentage of that key.
$callback->($k, \$v, $key_list);
}
pop @$key_list;
# Replace old hash values with the new ones
$hash->{$k} = $v;
}
}
hash_walk(\%prj, [], \&replace_all_val_strings);
sub replace_all_val_strings {
my ($k, $v, $key_list) = @_;
printf "k = %-8s v = %-4s key_list = [%s]\n", $k, $$v, "@$key_list";
$$v =~ s/oldstr/newstr/;
printf "k = %-8s v = %-4s key_list = [%s]\n", $k, $$v, "@$key_list";
}
如果您使用perl作为“CPAN解释器”,那么除此之外,还有一个非常简单的方法: 输出:
t => 10
y => 11
$a
和$b
在traverse()
函数中被视为特殊变量(与sort()
一样)<代码>数据::遍历是一个非常简单但非常有用的模块,没有非核心依赖项。您能给出一个更现实的例子吗。你在哪里遇到这样的结构?它是用来干什么的?你想做什么?也许另一种数据结构更适合此任务?@Aurril:嵌套的哈希结构对许多事情都很有用,请参阅下面我文章中的链接以获取示例。每个哈希是否有多个键?我相信其中一个perl xml解析器会将xml文件解析为哈希表的嵌套结构。这应该是$foo{$keyname}不是%foo{$keyname}!所以它应该是这样的。这就是我在喝咖啡之前发布的内容。在OP中,数据结构的第一个括号是花括号,表示它是散列引用。我的$hash={'key'=>{'key2'=>{'key3'=>'value}因此,您将需要取消引用此解决方案仅在定义了固定数量的子哈希的情况下有效。如果哈希结构是自动生成的,则需要更通用的方法。在我看来,递归算法将是更好的解决方案。我不熟悉Perl,否则我将给出一个示例。@ccheneson:无需取消引用。这就是它的作用所在是。+1谢谢,Data::Visitor
看起来很有用。从文档中看不出如何做一些简单的事情——例如,遍历嵌套哈希结构,打印叶值及其键(立即值和它们的祖先值).我相信这是可行的;我只需要把我的头绕一圈。:)我喜欢你在第四行的尤达状态:)
sub hash_walk {
my $self = shift;
my ($hash, $key_list, $callback) = @_;
while (my ($k, $v) = each %$hash) {
# Keep track of the hierarchy of keys, in case
# our callback needs it.
push @$key_list, $k;
if (ref($v) eq 'HASH') {
# Recurse.
$self->hash_walk($v, $key_list, $callback);
}
else {
# Otherwise, invoke our callback, passing it
# the current key and value, along with the
# full parentage of that key.
$callback->($k, \$v, $key_list);
}
pop @$key_list;
# Replace old hash values with the new ones
$hash->{$k} = $v;
}
}
hash_walk(\%prj, [], \&replace_all_val_strings);
sub replace_all_val_strings {
my ($k, $v, $key_list) = @_;
printf "k = %-8s v = %-4s key_list = [%s]\n", $k, $$v, "@$key_list";
$$v =~ s/oldstr/newstr/;
printf "k = %-8s v = %-4s key_list = [%s]\n", $k, $$v, "@$key_list";
}
use Data::Traverse qw(traverse);
my %test_hash = (
q => [qw/1 2 3 4/],
w => [qw/4 6 5 7/],
e => ["8"],
r => {
r => "9" ,
t => "10" ,
y => "11" ,
} ,
);
traverse { next if /ARRAY/; print "$a => $b\n" if /HASH/ && $b > 8 } \%test_hash;
t => 10
y => 11