比较和验证数据结构

时间:2012-03-04 10:41:22

标签: perl

我必须检查像这样的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。

问题是:这样做的最佳策略是什么?

我在考虑

  • 通过eval构建一系列子参考
  • 检查5个不同的预建subrefs中的适当的一个(每个案例一个&gt;,&lt;,&lt; =,&gt; =和==)

我是否完全走错了路?如果不是,最好的,评估的或预先建立的功能是什么?

我已经研究过Params :: Validate,但我担心它会产生大量开销,而且我还是要构建回调。

2 个答案:

答案 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的引用,即使这些变量在循环的当前迭代结束时超出范围。因此,在此之后,这些变量将被安全地移除,只能从我们创建的子程序访问。