Итерация над вложенным хешем в perl

Вопрос:

Я должен перебирать вложенный хэш в 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",
},
];

Я хочу перебирать subarray 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}";
}
}
}

Но это не работает. Я не понимаю, где я ошибаюсь. Любые указатели в правильном направлении были бы полезны.

Лучший ответ:

Попробуй это:

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

Ответ №1

У вас очень сложный объект данных, и вы уже столкнулись с проблемами, связанными с ним. Хотя я мог бы помочь вам решить вашу прямую проблему, я думаю, вам будет полезно узнать, как уменьшить сложность.

Perl поддерживает объектно-ориентированное программирование. Это позволяет вам принимать структуры данных и присоединять подпрограммы к ним, которые работают с ними. Вы можете прочитать о Perl OO здесь. Я покажу вам, как вы можете превратить список $featureGroup в список объектов и как получить доступ к features которые содержит один объект. Вы должны применять эту технику для каждого хэша в вашей структуре данных (вы можете оттолкнуть ее назад, если вы уверены, что определенные внутренние хэши не должны быть объектами, но, вероятно, лучше начать с переутомления, а затем отскочить назад, а не наоборот).

Это один из хэшей группы функций:

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

В этом случае у вас есть featureType, name и parameterMap. Эти поля не отображаются в каждом объекте в вашем списке (фактически последний хэш выглядит совсем по-другому, чем первые два). Я покажу вам, как создать объект, который требует этих трех параметров:

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?'
}
);

Затем вы можете получить доступ к этим полям с помощью названных accessors:

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();

Если вы примените это ко всем уровням вашего хэша, вы обнаружите, что ваш код становится легче управлять. Удачи!

Ответ №2

Вместо того, чтобы повторяться по индексу, я бы посоветовал вам повторять по элементу.

Это позволяет легко фильтровать каждый шаг с помощью grep или next

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

Оцените статью
TechArks.Ru
Добавить комментарий