2012-03-04 13 views
5

que tienen que comprobar hashrefs como ésteestructuras de datos La comparación y validación de

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

contra un arrayref de hashrefs condiciones como esta

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

expresar y devolver un valor verdadero si se cumplen todas las condiciones.

Ninguna de las dos estructuras de datos está predeterminada. Uno se construye a partir del análisis de una cadena en una base de datos, y el otro de analizar la entrada del usuario.

En el caso anterior, volvería cierto, pero si he comprobado la hashref contra

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

volvería falsa, porque foo en el primer hashref no es < = 60.

El La pregunta es: ¿cuál es la mejor estrategia para hacer eso?

Pienso en

  • la construcción de una serie de subrefs través eval
  • comprobación con el apropiado entre 5 subrefs pre-construidos diferentes (uno por cada caso de>, <, < =,> = y ==)

¿Estoy yendo por el camino equivocado? y si no, ¿cuál es la mejor, eval o funciones preconstruidas?

He examinado Params :: Validate pero me preocupa que sea una gran sobrecarga, y tendría que construir las devoluciones de todos modos.

+0

Una serie de referencias hash simples solo sería útil si tuviera claves duplicadas. P.ej. '[{foo => ...}, {foo => ...}]' Sospecho que no tiene claves duplicadas, lo que hace que esto sea redundante, y probablemente solo deba usar un hash, y omita la matriz. – TLP

Respuesta

7

Use referencias de código en su lugar, y tendrá listos validadores. Simplifiqué tu condición-estructura. No es necesario tener un nivel de matriz adicional allí, a menos que tenga claves duplicadas, lo que supongo que no es así.

La simplista sub { $_[0] <= 75 } simplemente comparará el primer valor de los argumentos. Por defecto, el último valor evaluado en la subrutina será su valor de retorno.

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

Salida:

bar : Invalid 
baz : Valid 
foo : Valid 
+0

Gracias por la respuesta. – simone

+0

@simone De nada. – TLP

1

Para construir sobre la respuesta de TLP, también puede crear fácilmente los submarinos anónima de su hash gama-de-existentes:

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

esto supone que solo tienes un cheque por cada campo en tu matriz original de hashes. Si es posible que tenga varios, las cosas se ponen un poco más complejo, pero siempre se puede hacer algo como esto:

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

Sal. En caso de que alguien se pregunte cómo puede funcionar este código, la respuesta es: closures.Específicamente, cuando esos subs anónimos se crean dentro del bucle, retienen referencias a las variables léxicas $num y $chain, incluso después de que estas variables salgan del alcance al final de la iteración actual del bucle. Entonces, para siempre, esas variables serán guardadas de forma segura, accesibles solo desde la subrutina que hemos creado.

Cuestiones relacionadas