Nikolan Asad
Nikolan Asad

Reputation: 178

iterating over structure with perl

im still beginner with perl , here im trying to loop over $struct->{'transferBatch'}->{'networkInfo'}; and its dump looks like :

$VAR1 = {
            'utcTimeOffsetInfo' => [
                                     {
                                       'utcTimeOffset' => '+0100',
                                       'utcTimeOffsetCode' => 0
                                     }
                                   ],
            'recEntityInfo' => [
                                 {
                                   'recEntityId' => '87.238.128.37',
                                   'recEntityType' => 2,
                                   'recEntityCode' => 0
                                 },
                                 {
                                   'recEntityCode' => 1,
                                   'recEntityType' => 2,
                                   'recEntityId' => '213.233.130.201'
                                 },
                                 {
                                   'recEntityId' => '353876999524',
                                   'recEntityCode' => 1,
                                   'recEntityType' => 1
                                 },
                                 {
                                   'recEntityCode' => 3,
                                   'recEntityType' => 1,
                                   'recEntityId' => '353876999523'
                                 }
                               ]
          };

i just want to get the recEntityCode where recEntityType = 2 and store it in veriable $recEntityCode_2 and same thing for recEntityType = 1 $recEntityCode_1 , only one value for each on of them just first catch then break out the loop

#!/usr/bin/perl -w

use strict;
use warnings;

use TAP3::Tap3edit;
use Data::Dumper;



printDir(".");
sub printDir{
opendir(DIR, $_[0]);
my @files;
my @dirs;
 (@files) = readdir(DIR);
 foreach my $file (@files) {
    if (-f $file and substr($file,0,2) eq "CD") {


     my $tap3 = TAP3::Tap3edit->new;

     my $tap_file = $file;
$tap3->decode($tap_file)  or  die $tap3->error; 

my $struct=$tap3->structure;

my $Tracker = $struct->{'transferBatch'};
if (defined $Tracker){



my $rectag = $struct->{'transferBatch'}->{'networkInfo'}->{'recEntityInfo'};

$count_1=0;
$count_2=0
foreach my $rectag1( @{$rectag} )
{
    if ($rectag1->{'recEntityType'} && int($rectag1->{'recEntityType'}) == 2){
      $var1_recEntityType = $rectag1->{'recEntityCode'}
      $count_1 = $count_1 + 1;
    }
    if ($rectag1->{'recEntityType'} && int($rectag1->{'recEntityType'}) == 1){
      $var1_recEntityType = $rectag1->{'recEntityCode'}
      $count_2 = $count_2 + 1;
    }
    if ($count_1 = 1 && $count_2 = 1)
    {
    break;
    }
}

print $recEntityCode_2;
print$recEntityCode_1;
$tap3->encode("$tap_file")  or  die $tap3->error; 

}
    }

 } 

 closedir(DIR);
}

Upvotes: 0

Views: 162

Answers (2)

s0me0ne
s0me0ne

Reputation: 516

Well, there're many solutions depending on what you exactly have and what you exactly want (TIMTOWTDI, you know). Do you know an exact number of entity types? Are you sure there's at least one array element for each of those entities?

The following code is rather dirty and proof-of-concept just to give you an idea, and it answers the literal question as it was asked (I assume your input hash is referenced as $r):

no strict;
no warnings;
use List::Util qw(first);

for my $type (1, 2) {
    ${qq|recEntityCode_$type|} = (first { $_->{recEntityType} == $type } $r->{recEntityInfo}->@*)->{recEntityCode};
}

print $recEntityCode_1 . "\n";
print $recEntityCode_2 . "\n";

For sure, I wouldn't use it. Much better way is to create a hash to store your results and not to declare separate variables for each of them:

use strict;
use warnings;
use List::Util qw(first);

my %recEntityCodes;

for my $type (1, 2) {
    $recEntityCodes{$type} = (first { $_->{recEntityType} == $type } $r->{recEntityInfo}->@*)->{recEntityCode};
}

print $recEntityCodes{1} . "\n";
print $recEntityCodes{2} . "\n";

Easy to see it is not optimal either, as we're walking the array from the start for each type (again, just to demonstrate one of possible solutions).

The simpliest solution I can invent out of my head is the following:


use strict;
use warnings;

my %recEntityCodes;

$recEntityCodes{$_->{recEntityType}} //= $_->{recEntityCode} for $r->{recEntityInfo}->@*;

print $recEntityCodes{1} . "\n";
print $recEntityCodes{2} . "\n";

Here we walk an array just once, but, on the other hand, we always walk the whole array.

Which one is the best is up to you. If you array is short enough you usually don't care and just take variant 3 as shortest code. If the array is large, either of variants 2 or 3 may be profitable depending on array properties. If the array is really huge, it worth optimizing further.

Upvotes: 2

Nikolan Asad
Nikolan Asad

Reputation: 178

I Don't know if there's another method for counter, but it Worked with me :

my $element;
$counter_rec2 = 0;
$counter_rec1 = 0;

foreach $element ( @{$struct->{'transferBatch'}->{'networkInfo'}->{'recEntityInfo'} } ) {

    if (defined $element->{recEntityType} && $element->{recEntityType}==2 && $counter_rec2 == 0 ) {
        $recEntityCode2=$element->{recEntityCode};
        $counter_rec2 = $counter_rec2 +1;
        print "recEntityCode: $recEntityCode2\n";
    }

    if (defined $element->{recEntityType} && $element->{recEntityType}==1 && $counter_rec1 == 0 ) {
        $counter_rec1 = $counter_rec1 +1;
        $recEntityCode1=$element->{recEntityCode};
        print "recEntityCode: $recEntityCode1\n";
    }

}

print "this is value for 2 $recEntityCode2\n";
print "this is value for 1 $recEntityCode1\n";

Upvotes: 2

Related Questions