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;
}
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;
I have problem with accessing a hash in each element of array after creating it but it gave the last element. What should I do to access all the elements of my array?
When I want push a hash to an array I use {} instead of () because if I don't it gave me error. How does it see when I use {}?
#stem = ();
for ($i = 0; $i < 2; ++$i) {
push #stem, { u1 => 1, u2 => 2 , u3 => 3 };
}
#ants = ();
$count = 0;
for ($i = 0; $i < scalar(#stem); ++$i) {
#allowed = ();
%hash = ();
for ($j = 0; $j < scalar(#stem); ++$j) {
push #allowed, { stem => ++$count, hinfo => ++$count };
}
%hash = (allowed => \#allowed, solution => ++$count);
push (#ants, \%hash);
}
for ($i = 0; $i < scalar(#ants); ++$i) {
%test = %{$ants[$i]};
print "=>", $test{solution}, "\n";
#temp = #{$test{allowed}};
for ($j = 0; $j < scalar(#temp); ++$j) {
print $j, ":", $temp[$j]->{stem}, " ", $temp[$j]->{hinfo}, "\n";
}
}
Output:
=>21
0:16 16
1:18 18
2:20 20
=>21
0:16 16
1:18 18
2:20 20
2) When I want push a hash to an array I use {} instead of () because if I don't it gave me error. How does it see when I use {}?
I can answer this Question 2.
When you use () perl sees as list of elements. When you use {} perl sees it as reference to a hash.
So When you do this: push #Arr, (x=>2, y=>5); four elements will be pushed to #Arr: x, 2, y, 5. Which is not your intention.
But When you do this: push #Arr , {x => 2, y => 5}; a single reference to an anonymous hash containing x and y as the keys, and 2 and 5 as the respective values will be pushed to #Arr.
I have a multidimensional hash of arrays that represent a student's grade in each subject for the first four assignments.
my %students_grades = (
Colton => {
English => [ 90, 95, 80, 75 ],
Mathematics => [ 77, 89,94, 100 ],
},
);
The syntax is a bit off but here's the code that creates the hash of arrays above.
#!/usr/bin/perl
my %students_grades;
$students_grades{'Colton'}{'English'}[0] = 90;
$students_grades{'Colton'}{'English'}[1] = 95;
$students_grades{'Colton'}{'English'}[2] = 80;
$students_grades{'Colton'}{'English'}[3] = 75;
$students_grades{'Colton'}{'History'}[0] = 77;
$students_grades{'Colton'}{'History'}[1] = 89;
$students_grades{'Colton'}{'History'}[2] = 94;
$students_grades{'Colton'}{'History'}[3] = 100;
How do I loop through the student's grades he received in History using a foreach loop? Right now I'm looping through it using a for loop.
my $num_of_grades = scalar #{$students_grades{'Colton'}{'History'}};
for (my $i=0; $i <= $num_of_grades; $i++) {
print $students_grades{'Colton'}{'History'}[$i] . "\n";
}
This is a representation of my code but in my actual program my hash of arrays is more complicated so I want to loop through the hash of arrays using a foreach loop because it'll be easier to handle. How do I do that?
for (my $i=0; $i<#array; ++$i) {
my $ele = $array[$i];
...
}
can be written simply as
for my $ele (#array) {
...
}
so you could have used the following:
for my $grade (#{ $students_grades{'Colton'}{'English'} }) {
print("$grade\n");
}
my $grade = $students_grades{'Colton'}{'English'}[0];
is short for
my $grade = $students_grades{'Colton'}->{'English'}->[0];
which means you can do
my $grades = $students_grades{'Colton'}{'English'};
my $grade = $grades->[0];
which means you could also have used the following:
my $grades = $students_grades{'Colton'}{'English'};
for my $grade (#$grades) {
print("$grade\n");
}
Knowing this allows one to easily escalate to the following:
for my $student_name (keys(%students_grades)) {
my $student_grades_by_class = $students_grades{$student_name};
for my $class_name (keys(%$student_grades_by_class)) {
my $grades = $student_grades_by_class->{$class_name};
for my $grade (#$grades) {
print("$student_name: $class_name: $grade\n");
}
}
}
In perl, for and foreach mean the same.
But the thing here is - you don't have a hash of arrays - you have a hash of array references.
So:
$students_grades{'Colton'}{'History'}
is actually an array reference.
So you can dereference it:
foreach my $grade ( #{ $students_grades{'Colton'}{'History'} } ) {
print "$grade\n";
}
I'm trying to compare 2 huge arrays and want to use map. I am using unique key concept here to match the indexes.
My Arrays:
my #array1 = ( ['a','b','c','d'], ['e','f','g','h'], ['i','j','k','l'], ['m','n','o','p'], ['q','r','s','t']);
my #array2 = ( ['r','q','s','t'], ['b','a','c','d'], ['n','m','o','p'], ['f','e','g','h'], ['j','i','k','l']);
My unique Keys:
my #uk1 = (0,2,3);
my #uk2 = (1,2,3);
These arrays will be huge in size, over 30,000 indexes in each with over 20 elements in each index.
So effectively i create a map where
for ( my $j = 0; $j <= $#array1 ; $j++ )
{
my searchString;
for ( my $k = 0; $k <= $#uk1; $k++ )
{
if ( $k != 0 )
{
$searchString .= ","
}
$my searchString .= $array1[$j][$uk[$k];
}
my #result = map { $_ }
grep { join (",",$array2[$_][1],$array2[$_][2],$array2[$_][3]) ) =~ join(",",$array1[$j][0],$array1[$j][1],$array1[$j][2]) }
0 .. $#array;
}
returns matched indexes.
My problem is, how do i make this dependant on the unique keys? as the length of the unique key will keep changing and as far as i know i cannot dynamically create the $array2[$_] join part.
Hope my question is clear enough.
I want to have the logic that compares
$array1[$uk1[0]],$array1[$uk1[1]],$array1[$uk1[2]] and so on (depending on the number of keys in UK) with
$array2[$uk2[0]],$array2[$uk2[1]],$array2[$uk2[2]].......
Perhaps,
my #array1 = ( ['a','b','c','d'], ['e','f','g','h'], ['i','j','k','l'], ['m','n','o','p'], ['q','r','s','t']);
my #array2 = ( ['r','q','s','t'], ['b','a','c','d'], ['n','m','o','p'], ['f','e','g','h'], ['j','i','k','l']);
my #result;
for my $i (0 .. $#array1) {
push #result,
map { [$i, $_] }
grep {
"#{ $array1[$i] }[1,2,3]" eq "#{ $array2[$_] }[0,2,3]"
}
0 .. $#array2;
}
use Data::Dumper; print Dumper \#result;
output
$VAR1 = [
[
0,
1
],
[
1,
3
],
[
2,
4
],
[
3,
2
],
[
4,
0
]
];
What you want to use is an array slice:
But lets also make life easier:
for my $sample ( #array1 )
{
my $test= join(",", #$sample[#uk1]) ;
my #result = grep { $_ eq $test } map { join(",", #$_[#uk2] ) } #array2 ;
say "huzzah" if #result ;
}
Perl lets you specify multiple elements from an array via the "array slice":
my #list= ('a', 'b', 'c', 'd') ;
my #pieces= #list[1,3] ;
I have an array and a hash:
#arraycodons = "AATG", "AAAA", "TTGC"... etc.
%hashdictionary = ("AATG" => "A", "AAAA" => "B"... etc.)
I need to translate each element of the array for the corresponding value in hashdictionary. However, I obtain a wrong translation.....
To see the problem, I have printed $codon (each element of the array), but each codon is repeated several times..... and It shouldn't.
sub translation() {
foreach $codon (#arraycodons) {
foreach $k (keys %hashdictionary) {
if ($codon == $k) {
$v = $hashdictionary{$k};
print $codon;
}
}
}
}
I don't know if I've explained my problem well enough, but I can't go on with my code if this doesn't work...
Many thanks in advance.
You appear to be looping through the keys of your hash (also known as a "dictionary") to find your desired key. This defeats the purpose of a hash (also known as a "dictionary") - the primary advantage of which is ultra fast lookups of a key.
Try, instead of
foreach $codon (#arraycodons) {
foreach $k (keys %hashdictionary) {
if ($codon == $k) {
$v = $hashdictionary{$k};
print $codon;
}
}
}
this:
foreach $codon (#arraycodons) {
my $value = $hashdictionary{$codon};
print( "$codon => $value\n" );
}
or:
foreach my $key ( keys %hashdictionary ) {
my $value = $hashdictionary{$key};
print( "$key => $value\n" );
}
my #mappedcodons = map {$hashdictionary{$_}}
grep (defined $hashdictionary{$_},#arraycodons);
or
my #mappedcodons = grep ($_ ne "", map{$hashdictionary{$_} || ""} #arraycodons);
my #words = ("car", "house", "world");
my %dictionary = ("car" => "el coche", "house" => "la casa", "world" => "el mundo");
my #keys = keys %dictionary;
foreach(#words) {
my $word = $_;
foreach(#keys) {
if($_ eq $word) { # eq, not ==
my $translation = $dictionary{$_};
print "The Spanish translation of $word is $translation\n";
}
}
}