Home > Net >  How to Iterate through multiple Perl arrays
How to Iterate through multiple Perl arrays

Time:10-07

I am hoping to make a loop that allows me to use less lines of code to make changes to a settings file with Perl. Currently my code reads an XML file and locates a settings ID and replaces the setting value in that ID with a new one. The current request involves a lot of changes to the settings file and the code is very long. I have set my values in an array and my settings ID's in an array. Like this:

@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');

and run the following.

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

I would like to run these changes through a loop just using the array [0] - [3] until completed as I have to do this same set of 4 multiple times. I am not too familiar with looping arrays. Is this something I can do in Perl? If so, what would be the most efficient way to do so?

CodePudding user response:

A simple take

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

I take it that you don't need all those individual $matchSunDP1G1 etc. It's assumed that the two arays always have the same length, and their elements are needed in pairs at same indices.

Then there are libraries that help with use of multiple arrays in parallel, that can be particularly useful when things get messier or more complicated. An example of using an iterator

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

If the lists are uneven in size the iterator keeps going through the length of the longer one. After the shorter one gets exhausted its would-be value is undef.

CodePudding user response:

Following code sample demonstrates how you could use %hash for alternation you try to achieve.

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

Reference: hash, hash operations

CodePudding user response:

Yet Another Way, using zip from the core List::Util module:

#!/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]);

}
  • Related