Сравнение и проверка структур данных - PullRequest
5 голосов
/ 04 марта 2012

Я должен проверить такие хеш-функции, как этот

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

против массива ссылок на хеш-выражения, выражающих условия, подобные этому

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

и вернуть истинное значение, если выполнены все условия.

Ни одна из двух структур данных не предопределена. Один основан на анализе строки в базе данных, другой - на анализе пользовательского ввода.

В случае выше, я бы возвратил true, но если бы я проверил хэш-ссылку с

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

Я бы вернул false, потому что foo в первом хэш-адресе не равен <= 60. </p>

Вопрос в том, какова лучшая стратегия для этого?

Я думаю о

  • построение серии подрефер через eval
  • проверка на соответствие одному из 5 различных предварительно созданных подрефсов (по одному на каждый случай для>, <, <=,> = и ==)

Я вообще иду по неверному пути? а если нет, то какие функции лучше, eval или pre-built?

Я посмотрел в Params :: Validate, но я обеспокоен тем, что это будет много накладных расходов, и мне все равно придется создавать обратные вызовы.

Ответы [ 2 ]

7 голосов
/ 04 марта 2012

Вместо этого используйте ссылки на коды, и вы будете готовы к работе с валидаторами.Я упростил вашу структуру условий.Там нет необходимости иметь дополнительный уровень массива, если только у вас нет дублирующих хеш-ключей, чего, как я полагаю, нет.

Упрощенный 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 голос
/ 04 марта 2012

Чтобы построить ответ 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;
}

Ps.Если кому-то интересно, как этот код может работать, ответ: замыкания .В частности, когда эти анонимные подпрограммы создаются внутри цикла, они сохраняют ссылки на лексические переменные $num и $chain даже после того, как эти переменные выходят из области видимости в конце текущей итерации цикла.Таким образом, навсегда после этого эти переменные будут безопасно спрятаны и доступны только из подпрограммы, которую мы создали.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...