2012-03-04 53 views
5

我要檢查hashrefs這樣一個比較和驗證數據結構

{ foo => 65, bar => 20, baz => 15 } 

對hashrefs的數組引用表達這樣

[ 
{ foo => { "<=" => 75 } }, 
{ bar => { "==" => 20 } }, 
{ baz => { ">=" => 5 } }, 
] 

條件,如果滿足所有條件返回真值。

這兩種數據結構都不是預先確定的。一個是通過解析數據庫中的字符串構建的,另一個解析用戶輸入。

在上述情況下,我將返回true,但如果我查了hashref對

[ 
{ foo => { "<=" => 60 } }, 
{ bar => { "==" => 20 } }, 
{ baz => { ">=" => 5 } }, 
] 

我將返回false,因爲FOO第一hashref不< = 60

的問題是:做這件事的最佳策略是什麼?

我想到的

  • 通過EVAL
  • 檢查對5種不同的預建subrefs(每箱一個用於>,<,< =,> =之中的適當的一個建造一系列subrefs的和==)

我會一起走錯路嗎?如果不是,什麼是最好的,評估或預建功能?

我已經看過Params :: Validate,但我擔心它會有很多開銷,而且我必須建立回調。

+0

單個哈希引用數組只有在您有重複鍵時纔有用。例如。 ''{{foo => ...},{foo => ...}]'我懷疑你沒有重複的鍵,這會導致冗餘,你應該使用一個散列,並跳過數組。 – TLP 2012-03-04 11:11:34

回答

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 
+0

感謝您的回答。 – simone 2012-03-04 23:20:50

+0

@simone不客氣。 – TLP 2012-03-04 23:26:26

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。特別是,當這些匿名子被創建在循環內部時,即使在循環的當前迭代結束時這些變量超出範圍之後,它們仍保留對詞法變量$num$chain的引用。所以,永遠之後,這些變量將會被安全地拋在一邊,只能從我們創建的子程序中訪問。