迭代perl中的嵌套哈希

时间:2014-07-23 09:11:43

标签: perl hash

我必须迭代perl中的嵌套哈希并执行一些操作。我的结构是

$featureGroup = [
  {
    featureType => "widget",
    name => "dpx-shadow-fleet",
    parameterMap => { dpxContext => "shadowAtf", dpxEndPoint => "/art/dp/ppd?" },
  },
  {
    featureType => "widget",
    name => "dpx-shadow-fleet",
    parameterMap => { dpxContext => "shadowBtf", dpxEndPoint => "/art/dp/btf?" },
  },
  {
    features => [
      {
        featuredesc => [
                         {
                           critical => 1,
                           featureType => "widget",
                           name => "dpx-ppd",
                           parameterMap => { dpxContext => "atf", dpxEndPoint => "/art/dp/" },
                         },
                         {
                           featureType => "widget",
                           name => "error",
                           parameterMap => { errorMessageId => "error" },
                         },
                       ],
        featureType => "sequence",
      },
      {
        critical    => 1,
        features    => ["encode-landing-image", "image-encoding-error"],
        featureType => "sequence",
      },
    ],
    handler => "/gp/product/features/embed-landing-image.mi",
    name => "embed-landing-image",
    pfMetrics => { "" => undef, "start" => sub { "DUMMY" }, "stop" => sub { "DUMMY" } },
    type => "custom-grid",
  },
];

我想遍历featuredesc子阵列并获取值名称。我正在尝试这个。

for(my $i = 0; $i < @$featureGroup; $i++){
  if(defined $featureGroup->[$i]->{'features'}){ 
     for(my $j = 0; $j < @$featureGroup->[$i]->{'features'} ; $j++){
       print "$featureGroup->[$i]->{'features'}->{'featuredesc}->{name}";
    }
   }
}

但这不起作用。我不明白我哪里错了。正确方向的任何指针都很有用。

3 个答案:

答案 0 :(得分:1)

你有一个非常复杂的数据对象,你已经遇到过处理它的问题。虽然我可以帮助您解决直接问题,但我认为您将从学习如何降低复杂性中获益更多。

Perl支持面向对象的编程。这允许您获取数据结构并将子例程附加到对它们进行操作的子例程。您可以阅读有关Perl OO here的信息。我将快速向您展示如何将$featureGroup列表转换为对象列表,以及如何访问单个对象包含的features。您应该将此技术应用于数据结构中的每个哈希值(如果您确定某些内部哈希值不应该是对象,则可以将其调整回来,但最好先过度使用它然后缩小而不是反过来)。

这是功能组哈希之一:

{
    'featureType' => 'widget',
    'name' => 'dpx-shadow-fleet',
    'parameterMap' => {
        'dpxContext' => 'shadowAtf',
        'dpxEndPoint' => '/art/dp/ppd?'
    }
}

在这一个中,您有featureTypenameparameterMap。这些字段不会出现在列表中的每个对象中(事实上,最后一个哈希值与前两个哈希值完全不同)。我将向您展示如何创建一个需要这三个参数的对象:

package Feature;

use Moose; # You may have to install this

has 'featureType' => (
    'is' => 'rw',
    'isa' => 'Str'
);
has 'name' => (
    'is' => 'rw',
    'isa' => 'Str'
);
has 'parameterMap' => (
    'is' => 'rw',
    'isa' => 'HashRef'
    # You could make this accept another object type
    # if you convert this inner hash
);

然后您可以像这样构建对象:

my $f = new Feature(
    'featureType' => 'widget',
    'name' => 'dpx-shadow-fleet',
    'parameterMap' => {
        'dpxContext' => 'shadowAtf',
        'dpxEndPoint' => '/art/dp/ppd?'
    }
);

然后,您可以使用命名的访问者访问这些字段:

print $f->name; # dpx-shadow-fleet

目前这似乎是一种使用哈希的更长方式,对吧?那么真正的好处来自于能够在类上定义任意子程序,从而隐藏调用者的复杂性。因此,您希望在原始问题中对features数组进行操作。让我们将其定义为一个字段:

has features => (
    is => 'rw',
    isa => 'ArrayRef[HashRef]'
    # This is an array containing hashes
    # You _really_ want to turn the inner hashes into an object here!
);

然后我们可以在另一个子程序中对它们进行操作。让我们定义一个返回作为序列的每个特征(具有featureType序列)的那个:

sub get_sequences {
    my ($self) = @_;

    return grep { $_->{featureType} eq 'sequence' } @{ $self->features };
}

现在,当您使用此类型的对象来获取序列功能时,您需要做的就是:

$f->get_sequences();

如果将此应用于哈希的所有级别,您会发现代码变得更容易管理。祝你好运!

答案 1 :(得分:0)

试试这个:

    for(my $i = 0; $i < @$featureGroup; $i++){
        if(defined $featureGroup->[$i]->{'features'}){
                for(my $j = 0; $j<scalar @{$featureGroup->[$i]->{'features'}} ; $j++){
                        for(my $k=0;$k<scalar @{$featureGroup->[$i]->{'features'}->[$j]->{'featuredesc'}};$k++) {
                                if (defined $featureGroup->[$i]->{'features'}->[$j]->{'featuredesc'}->[$k]->{'name'}) {
                                        print $featureGroup->[$i]->{'features'}->[$j]->{'featuredesc'}->[$k]->{'name'}."\n";
                                }
                        }
                        last if !defined $featureGroup->[$i+1]->{'features'};
                }
        }
}

答案 2 :(得分:0)

不是按索引迭代,而是建议您按元素迭代。

这使您可以使用grepnext

轻松过滤每个步骤
for my $group (grep {$_->{features}} @$featureGroup) {
    for my $feature (grep {$_->{featuredesc}} @{$group->{features}}) {
        for my $desc (@{$feature->{featuredesc}}) {
            print "$desc->{name}\n"
        }
    }
}

输出:

dpx-ppd
error