#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
is2
(индекс последнего значения в нем,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©»?