2012-03-04 37 views
5

tôi phải kiểm tra hashrefs như thế này mộtSo sánh và xác nhận cấu trúc dữ liệu

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

chống lại một arrayref của hashrefs bày tỏ những điều kiện như thế này

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

và trả về giá trị đúng nếu tất cả các điều kiện được đáp ứng.

Cả hai cấu trúc dữ liệu đều không được xác định trước. Một được xây dựng từ phân tích cú pháp một chuỗi trong cơ sở dữ liệu, một chuỗi khác phân tích cú pháp đầu vào của người dùng.

Trong trường hợp trên, tôi sẽ trở thành sự thật, nhưng nếu tôi đã kiểm tra các hashref chống

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

tôi sẽ trả về false, vì foo trong hashref đầu tiên không phải là < = 60.

Các câu hỏi là: chiến lược tốt nhất để làm điều đó là gì?

Tôi đang nghĩ đến việc

  • xây dựng một loạt các subrefs qua eval
  • kiểm tra đối với một trong những phù hợp trong 5 subrefs pre-xây dựng khác nhau (một cho mỗi trường hợp cho>, <, < =,> = và ==)

Tôi có đi sai đường dẫn không? và nếu không, các chức năng tốt nhất, eval hoặc được tạo sẵn là gì?

Tôi đã xem xét Params :: Validate nhưng tôi lo ngại rằng nó muốn được rất nhiều chi phí, và tôi sẽ phải xây dựng các callbacks anyway.

+0

Một mảng các tham chiếu băm đơn sẽ chỉ hữu ích nếu bạn có các khóa trùng lặp. Ví dụ. '[{foo => ...}, {foo => ...}]' Tôi nghi ngờ bạn không có các khóa trùng lặp, điều này làm cho dự phòng này trở nên thừa và bạn có thể chỉ cần sử dụng băm và bỏ qua mảng đó. – TLP

Trả lời

7

Sử dụng tham chiếu mã thay thế và bạn sẽ sẵn sàng để xác thực. Tôi đã đơn giản hóa cấu trúc điều kiện của bạn. Không cần phải có một mức độ mảng phụ trong đó, trừ khi bạn có các khóa băm trùng lặp, mà tôi cho rằng bạn không có.

Đơn giản sub { $_[0] <= 75 } sẽ chỉ đơn giản so sánh giá trị đầu tiên của đối số. Theo mặc định, giá trị cuối cùng được đánh giá trong chương trình con sẽ là giá trị trả về của nó.

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"; 
    } 
} 

Output:

bar : Invalid 
baz : Valid 
foo : Valid 
+0

Cảm ơn câu trả lời. – simone

+0

@simone Bạn được chào đón. – TLP

1

Để xây dựng dựa trên câu trả lời TLP, bạn cũng có thể dễ dàng tạo các tàu ngầm ẩn danh từ băm mảng of-hiện tại của bạn:

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}; 
} 

này giả định bạn chỉ có một kiểm tra cho mỗi trường trong mảng băm ban đầu của mình. Nếu bạn có thể có nhiều thứ, mọi thứ trở nên phức tạp hơn một chút, nhưng bạn luôn có thể làm điều gì đó như sau:

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; 
} 

Ps. Trong trường hợp ai đó tự hỏi mã này có thể hoạt động như thế nào, câu trả lời là: closures.Cụ thể, khi những người đăng ký ẩn danh được tạo bên trong vòng lặp, họ giữ tham chiếu đến các biến từ vựng $num$chain, ngay cả sau khi các biến này nằm ngoài phạm vi kết thúc vòng lặp hiện tại của vòng lặp. Vì vậy, mãi mãi sau đó, các biến đó sẽ được xóa an toàn, chỉ có thể truy cập từ chương trình con mà chúng tôi đã tạo ra.

Các vấn đề liên quan