Perl: 统计复杂数据结构中的元素数量

3

我对复杂数据结构还不熟悉。虽然我有些理解,但是取出数据方面有些难度。我使用Data::Dumper找到了当前问题的数据结构...

$VAR1 = {
      '4' => {
               'engine_coded' => 0,
               'name' => 'FILTER_1',
               'filter_actions' => {
                                     'X_Override_Queue_Level' => 'Value'
                                   },
               'filter_criteria' => [
                                      [
                                        'X_Charge',
                                        '=',
                                        'X_CHARGE_1'
                                      ]
                                    ]
             }
    };

我需要做的是确保给定一个过滤器名称(在这种情况下为“4”),"name"有一个值,以及"filter_actions"和"filter_criteria"。有没有人有最好的实现方法?非常感谢! Janie

问题标题似乎与您实际提出的问题不符 - 您需要在哪里计算元素? - Ether
3个回答

5
让我们将其分解成几个部分...
首先,创建一个函数来验证一个结构:
sub validate
{
    my ($data) = @_;

    # always return true for now
    return 1;
}

现在让我们开始填写细节...您想要使用过滤器名称作为验证检查的一部分,因此让我们将其添加为参数:

sub validate
{
    my ($data, $filter_name) = @_;

    # always return true for now
    return 1;
}

在进行任何其他操作之前,检查该过滤器名称是否存在作为键是有意义的;如果不存在,则验证失败:
sub validate
{
    my ($data, $filter_name) = @_;

    return if not exists $data->{$filter_name};

    # otherwise, return true
    return 1;
}

现在还要检查是否有值。由于哈希键中的定义是'存在'的超集(任何已定义的值也必须存在,但并非每个存在的值都需要被定义 - 因为undef可能是该值),因此可以省略第一个检查:

sub validate
{
    my ($data, $filter_name) = @_;

    return if not defined $data->{$filter_name};

    # otherwise, return true
    return 1;
}

我们已经检查了数据中是否存在filter_name键,并且已经定义,但在深入了解之前,我们需要确认它确实是一个哈希引用:
sub validate
{
    my ($data, $filter_name) = @_;

    return if not defined $data->{$filter_name};

    return if ref $data->{$filter_name} ne 'HASH';

    # otherwise, return true
    return 1;
}

现在在筛选器名称下查找“filter_actions”和“filter_criteria”键:
sub validate
{
    my ($data, $filter_name) = @_;

    return if not defined $data->{$filter_name};

    return if ref $data->{$filter_name} ne 'HASH';

    return if not defined $data->{$filter_name}{filter_actions};
    return if not defined $data->{$filter_name}{filter_actions};

    # otherwise, return true
    return 1;
}

就是这样!一定要阅读有关在perldoc perlreftootperldoc perlrefperldoc perldsc中使用perl数据结构的内容。


你可能还应该检查 $data->{filtername} 是否为哈希引用。 - DVK
一种更简洁的方式是 if ( ref( MY_DAYA_STRUCT ) ne ref( {} ) ) - DVK
@DVK:eq 'HASH'ne ref {} 只多一个字符(不需要 undef 检查,因为当值不是引用时,ref 返回 '' 而不是 undef)。 - Ether
抱歉造成困惑。简洁来自于删除第一个条件。ref{}与'HASH'之间是一种风格上的差异,我在这里学到了前者的方法(如果我没记错的话是来自brian d foy),并且真的很喜欢它,无论是从可读性方面还是从“不要使用魔法常量”的角度来看。 - DVK

0
这是我的看法。你只是检查过滤器中是否存在数据。如果你想要更多的结构验证,那部分稍后再进行。
use List::Util qw<first>;

sub validate_filter { 
    my ( $filters_ref, $filter_name ) = @_;
    my $filter  = $filter_name ? $filters_ref->{$filter_name} : $filters_ref;
    return 1 unless 
        my $missing 
            = first { !!$filter->{ $_ } } 
              qw<name filter_actions filter_criteria>
       ;
    if ( $missing ) { 
        Carp::croak( '"Missing '$missing' in filter!" );
    }
}

好的,我的第一印象是它会接受结构和名称,但当然如果您在调用时知道足够多的话

validate_filter( $filters, 4 );

你已经掌握了足够的知识来通过:

validate_filter( $filters->{4} );

因此,参数处理可能不是最容易理解的,但从参数传递的角度来看是有意义的。

如果您想要验证结构,可以选择这条路线。根据您的数据,我展示了一个验证失败的示例,如果给定的filter_criteria集群在每个第三个插槽中没有'='运算符。

就像这样:

use Carp       qw<croak>;
use List::Util qw<first>;
use Params::Util ();

sub _test { 
    return 1 if shift->( $_ );
    local $Carp::CarpLevel = $Carp::CarpLevel + 2;
    Carp::croak( shift );
}

my $validators 
    = { filter_actions => sub {
           croak 'filter_actions is not deinfed!' unless defined;
           _test( \&Params::Util::_HASH, 'filter_actions must be hash!' );
        }
      , filter_criters => sub {
            croak 'filter_criteria is not defined!' unless defined $crit;
            _test( \&Params::Util::_ARRAY, 'filter_criteria must be non-empty ARRAY!' );
            foreach ( @$crit ) { 
                _test( \&Params::Util::_ARRAY, 'criteria must be non-empty ARRAYs' );
                _test( sub { 
                           my $arr = shift;
                           return if @$arr % 3;
                           # return whether any slot in sequence is not '='
                           return !first { $arr->[$_] ne '=' } 
                                   # every 3 beginning at 1
                                   grep  { $_ % 3 == 1 } (1..$#$arr)
                                   ;
                       }
                     , 'criteria must be key-value pairs separated by equal sign!' 
                     );
            }
        }
    };

这将会改变validate_filter子程序,如下所示:

sub validate_filter { 
    my ( $filters_ref, $filter_name ) = @_;
    my $filter  = $filter_name ? $filters_ref->{$filter_name} : $filters_ref;
    return 1 unless 
        my $missing 
            = first { 
                  return 1 unless $filter->{ $_ };
                  return   unless my $validator = $validators->{ $_ };
                  local $_ = $filter->{ $_ };
                  return 1 if $validator->( $_ );
              } 
              qw<name filter_actions filter_criteria>
       ;
    if ( $missing ) { 
        Carp::croak( "Missing '$missing' in filter!" );
    }
}

0

您可以通过检查$var->{4}->{filter_actions}来访问filter_actions/etc。您可能需要查看perldsc,以了解Perl数据结构的全面概述。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接