我必须检查像这样的hashrefs
{ foo => 65, bar => 20, baz => 15 }
反对表示像这样的条件的hashrefs的arrayref
[
{ foo => { "<=" => 75 } },
{ bar => { "==" => 20 } },
{ baz => { ">=" => 5 } },
]
如果满足所有条件,则返回真值。
这两个数据结构都没有预先确定。一个是通过解析数据库中的字符串而构建的,另一个是通过解析用户输入来构建的。
在上面的例子中,我会返回true,但如果我检查了hashref
[
{ foo => { "<=" => 60 } },
{ bar => { "==" => 20 } },
{ baz => { ">=" => 5 } },
]
我会返回false,因为第一个hashref中的foo不是&lt; = 60。
问题是:这样做的最佳策略是什么?
我在考虑
我是否完全走错了路?如果不是,最好的,评估的或预先建立的功能是什么?
我已经研究过Params :: Validate,但我担心它会产生大量开销,而且我还是要构建回调。
答案 0 :(得分:7)
使用代码引用代替,您将准备好验证器。我简化了你的条件结构。除非你有重复的哈希键,否则不需要额外的数组级别,我认为你没有。
简单sub { $_[0] <= 75 }
将简单地比较参数的第一个值。默认情况下,子例程中计算的最后一个值将是其返回值。
use v5.10;
use strict;
use warnings;
my $in = { foo => 65, bar => 21, baz => 15 };
my $ref = {
foo => sub { $_[0] <= 75 } ,
bar => sub { $_[0] == 20 } ,
baz => sub { $_[0] >= 5 } ,
};
for my $key (keys %$in) {
if ($ref->{$key}($in->{$key})) {
say "$key : Valid";
} else {
say "$key : Invalid";
}
}
<强>输出:强>
bar : Invalid
baz : Valid
foo : Valid
答案 1 :(得分:1)
基于TLP的答案,您还可以轻松地从现有的哈希数组中创建匿名潜艇:
my $array_of_hashes = [
{ foo => { "<=" => 75 } },
{ bar => { "==" => 20 } },
{ baz => { ">=" => 5 } },
];
my $ref = {};
foreach my $entry ( @$array_of_hashes ) {
my ($key, $subhash) = %$entry;
my ($op, $num) = %$subhash;
$ref->{$key} = {
'<=' => sub { $_[0] <= $num },
'==' => sub { $_[0] == $num },
'>=' => sub { $_[0] >= $num },
}->{$op};
}
这假设您只对原始哈希数组中的每个字段进行一次检查。如果你可能有几个,事情会变得有点棘手,但你可以做这样的事情:
my $ref = {};
foreach my $entry ( @$array_of_hashes ) {
my ($key, $subhash) = %$entry;
my ($op, $num) = %$subhash;
my $chain = $ref->{$key} || sub {1};
$ref->{$key} = {
'<=' => sub { $_[0] <= $num and $chain->($_[0]) },
'==' => sub { $_[0] == $num and $chain->($_[0]) },
'>=' => sub { $_[0] >= $num and $chain->($_[0]) },
}->{$op} || $chain;
}
聚苯乙烯。如果有人想知道这段代码可能如何工作,答案是:closures。具体来说,当在循环内创建那些匿名subs时,它们会保留对词法变量$num
和$chain
的引用,即使这些变量在循环的当前迭代结束时超出范围。因此,在此之后,这些变量将被安全地移除,只能从我们创建的子程序访问。