Как выполнить итерацию по нескольким массивам Perl

#arrays #perl #iteration

Вопрос:

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

 @GreetGoalDP1 = (3, 5, 7, 10);
@GreetSIDSunDP1 = ('//xsd:Settings/xsd:Setting[@SID="7012"]/xsd:Value', 
'//xsd:Settings/xsd:Setting[@SID="7013"]/xsd:Value', 
'//xsd:Settings/xsd:Setting[@SID="7014"]/xsd:Value', 
'//xsd:Settings/xsd:Setting[@SID="7015"]/xsd:Value');
 

и выполните следующее.

 my($matchSunDP1G1) = $xpc->findnodes($GreetSIDSunDP1[0]);
$matchSunDP1G1->removeChildNodes();
$matchSunDP1G1->appendText($GreetGoalDP1[0]);
#GreetB
my($matchSunDP1G2) = $xpc->findnodes($GreetSIDSunDP1[1]);
$matchSunDP1G2->removeChildNodes();
$matchSunDP1G2->appendText($GreetGoalDP1[1]);
#GreetC
my($matchSunDP1G3) = $xpc->findnodes($GreetSIDSunDP1[2]);
$matchSunDP1G3->removeChildNodes();
$matchSunDP1G3->appendText($GreetGoalDP1[2]);
#GreetD
my($matchSunDP1G4) = $xpc->findnodes($GreetSIDSunDP1[3]);
$matchSunDP1G4->removeChildNodes();
$matchSunDP1G4->appendText($GreetGoalDP1[3]);
 

Я хотел бы выполнить эти изменения в цикле, просто используя массив [0] — [3], до тех пор, пока он не будет завершен, так как мне нужно выполнить один и тот же набор из 4 раз несколько раз. Я не слишком хорошо знаком с циклическими массивами. Это то, что я могу сделать в Perl? Если да, то каков был бы наиболее эффективный способ сделать это?

Ответ №1:

Простой дубль

 use warnings;
use strict;
...

for my $i (0..$#GreetGoalDP1) {
    my ($matchSunDP1G) = $xpc->findnodes( $GreetSIDSunDP1[$i] );
    $matchSunDP1G->removeChildNodes();
    $matchSunDP1G->appendText( $GreetGoalDP1[$i] );
}
 

Я так понимаю, что вам не нужны все эти индивидуальные $matchSunDP1G1 и т. Д. Предполагается, что два араи всегда имеют одинаковую длину, и их элементы нужны попарно с одинаковыми индексами.

Синтаксис $#aryname предназначен для последнего индекса в массиве @aryname и .. является оператором диапазона , поэтому 0 .. $#GreetGoalDP1 для вашего примера приведен список 0,1,2,3 .

Кроме того, существуют библиотеки, которые помогают использовать несколько массивов параллельно, что может быть особенно полезно, когда все становится более запутанным или сложным. Пример использования итератора

 use List::MoreUtils qw(each_array);

my $it = each_array @GreetSIDSunDP1, @GreetGoalDP1;

while ( my ($sidsun, $goal) = $it->() ) {
    my ($matchSunDP1G) = $xpc->findnodes($sidsun);
    $matchSunDP1G -> removeChildNodes();
    $matchSunDP1G -> appendText( $goal );
}
 

Если списки неравномерны по размеру, итератор продолжает проходить по длине более длинного списка. После того, как более короткий будет исчерпан, его потенциальная ценность будет undef равна .

Комментарии:

1. Спасибо вам за обратную связь. Я дал простую попытку и смог получить первое значение для обновления, но оставшееся значение в массиве не изменилось. Я полагаю, что это может быть связано с тем, что $matchSunDP1 также должен меняться с каждым циклом. Правильно ли это звучит? Есть ли способ просто увеличить число на 1 в каждом цикле до конца $matchSunDP1?

2. @TaylorStevens Это странно-элементы $GreetSIDSunDP1[$i] и $GreetGoalDP1[$i] точно такие же, как те, которые были набраны вручную в вопросе. Все, что делает первый фрагмент ответа, — это помещает эти индексы в цикл вместо того, чтобы вводить их вручную. И $matchSunDP1G каждый раз делается заново, даже объявляется заново (это my спереди). Я не вижу, что может быть по-другому (неправильно) с циклом?

3. @TaylorStevens Исправил опечатки — пропущено закрытие ) , и я добавил G к имени (это не имеет значения)

4. @TaylorStevens Ах, это все объясняет. Синтаксис $#aryname предназначен для индекса последнего элемента в массиве @aryname . (Этот код всегда был $#GreetGoalDP1 , должно быть, потерялся, когда вы его скопировали.) Так что для @ary = (5,6,7); $#ary is 2 (индекс последнего значения в нем, 7 ). Это .. » оператор диапазона «, и когда мы говорим 0 .. 3 , что это расширено (0, 1, 2, 3) . Итак 0 .. $#ary (с массивом в этом примере) есть 0..2 , значит, список 0, 1, 2 . В вашем вопросе есть четыре элемента, поэтому цикл повторяется 0,1,2,3 .

5. @TaylorStevens Позвольте мне сказать это на всякий случай: убедитесь, что всегда есть use warnings; в начале программы. Он улавливает все виды плохих вещей, это действительно очень полезно. (Я подозреваю, что здесь это сказало бы вам о чем-то неправильном из-за ошибки копирования-вставки.) Тогда есть еще один хороший use strict; , который заставляет вас заявлять о вещах my .

Ответ №2:

Следующий пример кода демонстрирует, как вы могли бы использовать %hash для чередования, которого вы пытаетесь достичь.

 my %hash = (
        3   => '//xsd:Settings/xsd:Setting[@SID="7012"]/xsd:Value',
        5   => '//xsd:Settings/xsd:Setting[@SID="7013"]/xsd:Value',
        7   => '//xsd:Settings/xsd:Setting[@SID="7014"]/xsd:Value',
        10  => '//xsd:Settings/xsd:Setting[@SID="7015"]/xsd:Value')
);

while( my($k,$v) = each %hash ) {
    my $match = $xpc->findnodes($v);
    $match->removeChildNodes();
    $match->appendText($k);
}
 

Ссылка: хэш, операции хэширования

Ответ №3:

Еще один способ, используя zip из основного List::Util модуля:

 #!/usr/bin/env perl
use warnings;
use strict;
use List::Util qw/zip/;

...;

my @GreetGoalDP1 = (3, 5, 7, 10);
my @GreetSIDSunDP1 = ('//xsd:Settings/xsd:Setting[@SID="7012"]/xsd:Value', 
'//xsd:Settings/xsd:Setting[@SID="7013"]/xsd:Value', 
'//xsd:Settings/xsd:Setting[@SID="7014"]/xsd:Value', 
'//xsd:Settings/xsd:Setting[@SID="7015"]/xsd:Value');

foreach my $pair (zip @GreetSIDSunDP1, @GreetGoalDP1) {
    my ($matchSunDP1G1) = $xpc->findnodes($pair->[0]);
    $matchSunDP1G1->removeChildNodes();
    $matchSunDP1G1->appendText($pair->[1]);

}
 

Комментарии:

1. Должно быть авторское право на это YAW (еще одним способом), Ну, по крайней мере, широко распространять 🙂

2. @zdim «Есть более чем один способ сказать TMTOWTDI©»?