ExploitZ
ExploitZ

Reputation: 9

How to iterate through an Array of hashes in Perl?

I have the following array:

ifNameList -> $VAR1 = [
          {
            'VALUE' => ' gpon_olt-1/1/1',
            'ASN1' => '285278465'
          },
          {
            'VALUE' => ' gpon_olt-1/1/2',
            'ASN1' => '285278466'
          },
          {
            'VALUE' => ' gpon_olt-1/1/3',
            'ASN1' => '285278467'
          },
          {
            'VALUE' => ' gpon_olt-1/1/4',
            'ASN1' => '285278468'
          },
          {
            'VALUE' => ' gpon_olt-1/1/5',
            'ASN1' => '285278469'
          },
]

I need to iterate through this array of hashes comparing the "VALUE" field of each hash, until it matches and do some action.

I've already made the following code, but its not working. What I'm doing wrong?

sub GetIfIndexFromName{
    my $ifName = shift;
    my @ifList = shift;
    my $index;
    
    for (@ifList){
        my %interfaceHash = %$_;
        # Just trims any blank space on the string:
        $interfaceHash->{"VALUE"} =~ s/^\s+|\s+$//g;
        if($interfaceHash->{"VALUE"} eq $ifName){
            print "trimmed interface name-> ".$interfaceHash->{"VALUE"}."\n\n";
            $index = $interfaceHash->{"ASN1"};
        }
        
    }
    
    print "Returning index value: ".$index;
    return $index;
}

Upvotes: 0

Views: 54

Answers (1)

ikegami
ikegami

Reputation: 386646

Two errors.


Problem 1: Wrong variable

ALWAYS use use strict; use warnings;. It would have found this error:

# Access the `VALUE` element of the hash referenced by `$interfaceHash`.
$interfaceHash->{"VALUE"}

You have no variable named $interfaceHash.

There are three ways to fix this:

for ( @ifList ) {
   my %interfaceHash = %$_;
   ... $interfaceHash{ VALUE } ...
}
for my $interfaceHash ( @ifList ) {
   ... $interfaceHash->{ VALUE } ...
}

The latter is recommended. It avoids creating a copy of the hash, which involves create a number of temporary scalars. This is all useless work.


Problem 2: Incorrect parameter retrieval

The following is wrong:

my @ifList = shift;

shift returns a scalar. There's absolutely no point in using an array to hold exactly one scalar at all times.

sub GetIfIndexFromName {
    my $ifName = shift;
    my $ifList = shift;
   
    for ( @$ifList ) {
       ...
    }
}

# Pass a reference to the array.
GetIfIndexFromName( $ifName, $VAR1 )
sub GetIfIndexFromName {
    my $ifName = shift;
    my @ifList = @_;
   
    for ( @ifList ) {
       ...
    }
}

# Pass each element of the array.
GetIfIndexFromName( $ifName, @$VAR1 )

The former convention is more efficient, but the latter can create cleaner code in the caller. Probably not in your program, though.


How I'd write this:

use strict;
use warnings;
use feature qw( say );

use List::Util qw( first );

sub trim_inplace { $_[0] =~ s/^\s+|\s+\z//g; }

my @ifList = ...;
my $ifName = ...;

trim_inplace( $_->{ VALUE } ) for @ifList;

my $match = first { $_->{ VALUE } eq $ifName } @ifList
   or die( "Interface not found.\n" );

my $asn1 = $match->{ ASN1 };

say $asn1;

Upvotes: 1

Related Questions