我完全误解了你的问题。要查找键与正则表达式匹配的 散列 的数量(而不是 single 散列中匹配正则表达式的 键 的数量),您仍然可以使用我在之前的回答中概述的grep 方法。但是,这一次,您需要遍历您的哈希(如果您有 600 万个哈希,我假设您将它们存储在一个数组中)并在每个哈希上运行两次 grep:
#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
my @array = (
{ AA00 => 'foo' },
{ AB10 => 'bar' },
{ AA001 => 'foo' },
{ AA00 => 'foo', AB10 => 'bar' }
);
my ($hashes_with_aa00, $hashes_with_ab10, $hashes_with_both) = (0, 0, 0);
foreach my $hash (@array) {
my $aa_count = grep { /^AA00/ } keys %$hash;
my $ab_count = grep { /^AB10/ } keys %$hash;
$hashes_with_aa00++ if $aa_count;
$hashes_with_ab10++ if $ab_count;
$hashes_with_both++ if $aa_count and $ab_count;
}
say "AA00: $hashes_with_aa00";
say "AB10: $hashes_with_ab10";
say "Both: $hashes_with_both";
输出:
AA00: 3
AB10: 2
Both: 1
这可行,但在性能方面很差:grep 循环遍历每个哈希键列表中的 每个 元素,我们称它为 两次 em> 每个哈希!
由于我们不关心每个哈希中有多少键匹配,只关心是否存在 匹配,更好的解决方案是 any from List::MoreUtils。 any 的工作方式与grep 非常相似,但一旦找到匹配项就会返回。要使用any 而不是grep,请更改:
foreach my $hash (@array) {
my $aa_count = grep { /^AA00/ } keys %$hash;
my $ab_count = grep { /^AB10/ } keys %$hash;
$hashes_with_aa00++ if $aa_count;
$hashes_with_ab10++ if $ab_count;
$hashes_with_both++ if $aa_count and $ab_count;
}
到这里:
use List::MoreUtils 'any';
foreach my $hash (@array) {
my $aa_exists = any { /^AA00/ } keys %$hash;
my $ab_exists = any { /^AB10/ } keys %$hash;
$hashes_with_aa00++ if $aa_exists;
$hashes_with_ab10++ if $ab_exists;
$hashes_with_both++ if $aa_exists and $ab_exists;
}
请注意,我更改了变量名称以更好地反映它们的含义。
这在性能方面要好得多,但正如 Borodin 在对您的问题的评论中指出的那样,由于不使用特定键访问哈希,您正在失去哈希的速度优势。您可能希望相应地更改数据结构。
原答案:计算与 单个散列中的正则表达式匹配的键
这是我基于对您问题的误解的原始答案。我将其搁置是因为我认为它可能对类似情况有用。
要计算单个哈希中匹配正则表达式的键数,您可以使用grep:
my $aa_count = grep { /^AA00/ } keys %hash;
my $ab_count = grep { /^AB10/ } keys %hash;
my $both = $aa_count + $ab_count;
正如 HunterMcMillen 在 cmets 中指出的那样,无需再次搜索哈希键即可获得总数;在这种情况下,您可以简单地将两个小计相加。您可以摆脱这种情况,因为您要搜索的两种模式是互斥的;换句话说,您不能拥有一个既以AA00 和 AB10 开头的密钥。
在更一般的情况下,单个键可能会匹配两种模式(感谢 Borodin)。在这种情况下,您不能简单地将两个小计相加。例如,如果您希望您的密钥仅在字符串中的任何位置包含AA00 或AB10,不一定在开头,您需要执行以下操作:
my $aa_count = grep { /AA00/ } keys %hash;
my $ab_count = grep { /AB10/ } keys %hash;
my $both = grep { /(?:AA00|AB10)/ } keys %hash;
请注意,这会多次调用grep,这意味着多次遍历整个哈希。这可以使用像 FlyingFrog 和 Kenosis 那样的单个 for 循环更有效地完成。