我有一个哈希,我不知道它的深度。我得到了DBI::selectall_hashref
,其中第二个参数由用户给出。
因此,根据查询,我可以为2级哈希提供类似的内容。
hash_ref = (
aphrodite => (
foo => (
name => aphrodite,
foobar => foo
a => 1,
b => 2,
)
bar => (
name => aphrodite,
foobar => bar
a => 1,
b => 2,
)
)
apollo => (
...
)
ares => (
...
)
)
正如您所看到的,key
列在哈希值中是多余的。我想删除冗余密钥。
如果我知道这是一个2级哈希,我可以轻松解决我的问题:
for my $name (keys $hash_ref) {
for my $foobar (keys $hash_ref->{$name}) {
my $h = $hash_ref->{$name}{$foobar};
delete $h->{name};
delete $h->{foobar};
}
}
然而,对于3级哈希,我将需要3个级联for循环,依此类推。
如何动态删除
$hash_ref
中的冗余密钥,例如name
和foobar
?
我最初的想法是递归迭代我的哈希:
iterate($hash_ref, scalar @keys);
sub iterate {
my ($ref, $depth) = @_;
for(keys $ref) {
if ($depth > 0) {
iterate($ref->{$_}, $depth - 1);
}
else {
delete $ref->{$_} for(@keys);
}
}
}
它有效,但它很难看,非常难看......在继续前行之前,我想知道我是否错过了什么。也许我认为解决方案可能更简单。
有什么想法吗?
我正在编写一个数据库提取程序,它接受包含SQL查询$sql
和哈希键@keys
的用户配置。所以我从数据库中获取了值:
$dbh->selecthall_hashref($sql, \@keys, {}, @bind);
我还必须根据附加内容清理提取的数据。应用这些规则,我必须迭代到最深的$hash_ref
级别来访问键/值。
答案 0 :(得分:2)
我认为这可以满足您的需求。本质上,它通过散列进行递归,直到找到散列值不是引用的层。然后,它使用@keys
use strict;
use warnings;
use 5.010;
use Data::Dump;
use List::Util 'any';
my $hash_ref = {
aphrodite => {
bar => { name => "aphrodite", foobar => "bar", a => 3, b => 4, },
foo => { name => "aphrodite", foobar => "foo", a => 1, b => 2, },
},
apollo => {
bar => { name => "apollo", foobar => "bar", a => 7, b => 8, },
foo => { name => "apollo", foobar => "foo", a => 5, b => 6, },
},
ares => {
bar => { name => "ares", foobar => "bar", a => 11, b => 12, },
foo => { name => "ares", foobar => "foo", a => 9, b => 10, },
},
};
my @keys = qw/ name foobar /;
remove_dups($hash_ref, \@keys);
dd $hash_ref;
sub remove_dups {
my ($href, $keys) = @_;
if ( any { ref } values %$href ) {
remove_dups($_, $keys) for values %$href;
}
else {
delete @{$href}{@$keys};
}
}
<强>输出强>
{
aphrodite => { bar => { a => 3, b => 4 }, foo => { a => 1, b => 2 } },
apollo => { bar => { a => 7, b => 8 }, foo => { a => 5, b => 6 } },
ares => { bar => { a => 11, b => 12 }, foo => { a => 9, b => 10 } },
}