在不遍历整个哈希表的情况下,在子哈希中查找键

3

我有一个看起来像这样的哈希表:

my $hash = {
    level1_f1 => {
                  level2_f1 => 'something',
                  level2_f2 => 'another thing'
    },
    level1_f2 => {
                  level2_f3 => 'yet another thing',
                  level2_f4 => 'bla bla'
                  level2_f5 => ''
    }
...
 }

我还得到了一份与“level2”键对应的值列表,我想知道它们是否存在于哈希表中。 @list =(“level2_f2”,“level2_f4”,“level2_f99”) 我不知道@list中的每个元素属于哪个“level1”键。我能想到的唯一找到它们是否存在的方法是使用foreach循环遍历@list,另一个foreach循环遍历%hash的键并检查。
foreach my $i (@array) {
  foreach my $k (keys %hash) {
     if (exists $hash{$k}{$list[$i]})
 }
}

但我想知道是否有更有效或更优雅的方法来完成它。我发现的所有答案都要求您知道“level1”键,而我不知道。

谢谢!!

3个回答

5

使用

for my $inner_hash (values %$hash) {
    say grep exists $inner_hash->{$_}, @list;
}

1
你需要循环遍历所有的一级键。但如果你不需要知道哪些键匹配,只关心任何一个是否存在,那么你就不必显式地询问列表中的每个成员。你可以这样说:
foreach my $k (keys %hash) {
   if ( @{ $hash{$k} }{ @list } )
   {
   }
}

哈希切片将返回子哈希中与列表中键匹配的所有值。列表中不在子哈希中的键将被忽略。
然而要注意,这可能比你实际需要的更加繁琐。

1
你不需要遍历“整个哈希表”。
由于要检查每个值,因此必须遍历外层哈希表的元素,但不需要遍历内层哈希表的元素。 你的解决方案已经证明了这一点。
因此,你的解决方案在可伸缩性方面是尽可能高效的。你只能执行小优化,例如找到匹配项后立即停止。
for my $i (@list) {
   while ( my (undef, $inner) = each(%hash) ) {
      if (exists($inner->{$i}) {
         ...
         last;
      }
   }

   keys(%hash);   # Reset iterator since it might not be exhausted.
}

作为一种微小的优化,颠倒循环的嵌套可能会有益。
my %list = map { $_ => 1 } @list;

while ( my (undef, $inner) = each(%hash) ) {
   while (defined( my $k = each(%$inner) )) {
      if ($list{$k}) {
         delete($list{$k});
         ...
         last if !keys(%list);
      }

   }

   keys(%$inner);   # Reset iterator since it might not be exhausted.
   last if !keys(%list);
}

keys(%hash);   # Reset iterator since it might not be exhausted.

如果哈希值很小,这些更改实际上可能会减慢速度。
老实说,如果真的存在速度问题,那么问题在于您使用了错误的数据结构来运行所需的查询类型!

你认为对于这个问题来说,什么样的数据结构会更好呢?我倾向于总是考虑哈希表。 - Matias Irazoqui
哪种数据结构可以快速检查它是否包含一个字符串?其中之一是以你想要搜索的字符串为键的哈希表。(与你现有的情况相反:一个值为哈希表的哈希表,其键为你想要搜索的字符串。) - ikegami

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