Hashes array elements copy - arrays

My array of hashes:
#cur = [
{
'A' => '9872',
'B' => '1111'
},
{
'A' => '9871',
'B' => '1111'
}
];
Expected result:
#curnew = ('9872', '9871');
Any simple way to get only the values of the first hash element from
this and assign it to an array?

Mind that hashes are unordered, so I take the word first to mean lexicographically first.
map { # iterate over the list of hashrefs
$_->{ # access the value of the hashref
(sort keys $_)[0] # … whose key is the first one when sorted
}
}
#{ # deref the arrayref into a list of hashrefs
$cur[0] # first/only arrayref (???)
}
The expression returns qw(9872 9871).
Assigning an arrayref to an array as in #cur = […] is probably a mistake, but I took it at face value.
Bonus perl5i solution:
use perl5i::2;
$cur[0]->map(sub {
$_->{ $_->keys->sort->at(0) }
})->flatten;
The expression returns the same values as above. This code is a bit longer, but IMO more readable because the flow of execution goes strictly from top to bottom, from left to right.

First your array have to be defined as
my #cur = (
{
'A' => '9872',
'B' => '1111'
},
{
'A' => '9871',
'B' => '1111'
}
);
Note the parenthesis
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dump qw(dump);
my #cur = (
{
'A' => '9872',
'B' => '1111'
},
{
'A' => '9871',
'B' => '1111'
}
);
my #new;
foreach(#cur){
push #new, $_->{A};
}
dump #new;

use Data::Dumper;
my #hashes = map (#{$_}, map ($_, $cur[0]));
my #result = map ($_->{'A'} , #hashes);
print Dumper \#result;

Related

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

How do I append a new hash to an array of hashes?

If I wanted to add a new hash to all the arrays in the mother_hash using a loop, what would be the syntax?
My hash:
my %mother_hash = (
'daughter_hash1' => [
{
'e' => '-4.3',
'seq' => 'AGGCACC',
'end' => '97',
'start' => '81'
}
],
'daughter_hash2' => [
{
'e' => '-4.4',
'seq' => 'CAGT',
'end' => '17',
'start' => '6'
},
{
'e' => '-4.1',
'seq' => 'GTT',
'end' => '51',
'start' => '26'
},
{
'e' => '-4.1',
'seq' => 'TTG',
'end' => '53',
'start' => '28'
}
],
#...
);
If you have a hash of arrays of hashes and want to add a new hash to
the end of each of the arrays, you can do:
push #{ $_ }, \%new_hash for (values %mother_hash);
This loop iterates over the values of %mother_hash (which are array refs in this case) and setting $_ for each iteration. Then in each iteration, we push the reference to the new hash %new_hash to the end of that array.
First I would point out the daughter hashes aren't hashes but arrays of anonymous hashes. To add another daughter hash:
$mother_hash{daughter_hash3} = [ { %daughter_hash3 } ];
This creates an anonymous array that contains an anonymous hash with the contents of %daughter_hash3.
For a loop:
$mother_hash{$daughter_hash_key} = [ { %daughter_hash } ];
where $daughter_hash_key is a string contain the key for the %mother_hash and %daughter_hash is the hash to add.
To add another hash to a daughter array with key $daughter_hash_key:
push #{ $mother_hash{$daughter_hash_key} }, { %daughter_hash };
I know ti's complicated but I suggest you use Data::Dumper to dump the contents of %mother_hash each time thru the loop to see if it grows correctly.
use Data::Dumper;
print Dumper \%mother_hash;
See perldoc Data::Dumper for details..
Data::Dumper is a standard module that comes with Perl. For a list of standard modules, see perldoc perlmodlib.
mother_hash is a hash of arrays of hashes.
To add another top-level array of hashes.
%mother_hash{$key} = [ { stuff }, { stuff } ];
To add another entry to an existing array
push #{%mother_hash{'key'}} { stuff };
To add another entry to the hash in the embedded array
%{#{%mother_hash{'top_key'}}[3]}{'new_inner_key'} = value;
When confused and attempting to match up the "types" of hash / array / scalar containing a hash reference / array reference, you can use the following technique
use Data::Dumper;
$Data::Dumper::Terse = 1;
printf("mother_hash reference = %s\n", Dumper(\%mother_hash));
printf("mother_hash of key 'top_key' = %s\n", Dumper(%mother_hash{top_key}));
and so on to find your way through a large data structure and validate that you are narrowing down to the region you want to access or alter.

Dereferencing an array reference from a nested Perl hash

I hope I've stated that subject correctly. I have a hash of hashes that I've built from reading a file. The outer hash is groups, then the inner hash is parameters within that group. Each parameter value can either be a scalar or array, and the arrays can start at either zero or one.
I've written a subroutine that returns the value of a parameter. The calling function has to figure out whether the returned value is a scalar or an array. Works fine for scalars. Returns a reference to an array for array values (looks like ARRAY(0x004f00)). Using Data::Dumper spits out data that looks like an array, but I can't figure out how to dereference it in the code. Can someone point to what I'm doing wrong?
%HoH = (
flintstones => {
husband => "fred",
possessions => [ undef, "car", "record player", "rock" ],
pal => "barney",
pets => [ "bird", "dinosaur" ],
},
);
get_value("possessions");
sub get_value {
my $what_i_want = shift;
#groups = keys(%HoH);
foreach my $group ( #groups ) {
foreach my $param ( keys( %{ HoH {group} } ) ) {
if ( $param eq $what_i_want ) {
return $HoH{$group}{$param};
}
}
}
}
The caller assigns the return value to an array, #return, so in the case of a scalar it should put the value in $return[0].
In the case of an array, it should populate the array. When I call Dumper, it prints out scalars in single quotes and arrays in square brackets, as it should. However, when I use scalar(#return) to check the size of the array, it returns 1.
I've tried dereferencing the return statement using square brackets at the end to see if I could even get a scalar returned, but no luck.
You don't show the subroutine being called in context, but a quick fix would be to put this after the call
#return = #{ $return[0] } if ref $return[0]
Update
You're missing the point of hashes. You can access the correct element of the parameter hash by using $what_i_want as a hash key
I suggest you change your subroutine code to look like this
for my $group ( keys %HoH ) {
my $ret = $HoH{$group}{$what_i_want};
return unless defined $ret;
return ref $ret ? #$ret : $ret;
}
That way it will never return a reference
Update 2
Here's your complete program modified as I suggested
use strict;
use warnings 'all';
my %HoH = (
flintstones => {
husband => "fred",
possessions => [ undef, "car", "record player", "rock" ],
pal => "barney",
pets => [ "bird", "dinosaur" ],
},
);
my #return = get_value('possessions');
use Data::Dump;
dd \#return;
sub get_value {
my ($wanted) = #_;
for my $group ( keys %HoH ) {
my $ret = $HoH{$group}{$wanted};
if ( defined $ret ) {
return ref $ret ? #$ret : $ret;
}
}
return;
}
output
[undef, "car", "record player", "rock"]

How do I store an array as a value in a Perl hash?

I'm trying to create a hash in Perl, whose values are arrays. Something like:
my #array = split(/;/, '1;2');
my $hash = {'a' => #array};
Surprisingly, this reports (using Data::Dumper):
$VAR1 = {
'a' => '1',
'2' => undef
};
This page gives an example of storing an array in a hash by defining the array use square brackets, like:
my $hash = {'a' => ['1', '2']};
That works, but I'm getting my array from a call to the split method. What's magic about square brackets versus parentheses for defining an array, and how can I turn a "parentheses-array" into a 'square-brackets' array?
The values of hash (and array) elements are scalars, so you can't store an array into a hash.
The following are all equivalent:
my $hash = { a => #array };
my $hash = { 'a', #array };
my $hash = { 'a', $array[0], $array[1] };
my $hash = { a => $array[0], $array[1] => () };
A common solution is to store a reference to the array.
my #array = split(/;/, '1;2');
my $hash = { a => \#array }; # my $hash = { a => [ '1', '2' ] };
[ LIST ] similarly create an array, assigns LIST to it, then returns a reference to the array.

Array in value of hash perl

Is it possible to assign the reference of an array as the value in the key : value pair of a hash table in perl?
Yes it is. Create a reference to the array by using backslash:
$hash{key} = \#array;
Note that this will link to the actual array, so if you perform a change such as:
$array[0] = "foo";
That will also mean that $hash{key}[0] is set to "foo".
If that is not what you want, you may copy the values by using an anonymous array reference [ ... ]:
$hash{key} = [ #array ];
Moreover, you don't have to go through the array in order to do this. You can simply assign directly:
$hash{key} = [ qw(foo bar baz) ];
Read more about making references in perldoc perlref
Yes. See http://perlmonks.org/?node=References+quick+reference for some basic rules for accessing such data structures, but to create it, just do one of these:
%hash = ( 'somekey' => \#arrayvalue );
$hash{'somekey'} = \#arrayvalue;
%hash = ( 'somekey' => [ ... ] );
use Data::Dumper; #name=('5/17',
'5/17','5/17','5/17','5/17','5/17','5/17','5/17'); #status_flags=('U
H L','U C','U H L','U C','U C','U H L','U C', 'U H L');
#ip_address=('192.168.0.11','192.168.0.2','192.168.0.13','192.168.0.0','192.168.0.3','192.168.0.12','192.168.0.4','192.168.0.14'); #dp_id=('0','0','0','0','0','0','0','0');
#ip_prefix_length=('32','32','32','24', '32', '32','32','32');
for ($value=0;$value<=5;$value++) {
$keyvals{'Response'}{'brocade-extension-ip-route'}{'extension-ip-route'}={'name'=>"$name[$value]"};
$keyvals{'Response'}{'brocade-extension-ip-route'}{'extension-ip-route'}={'dp-id'=>"$dp_id[$value]"};
$keyvals{'Response'}{'brocade-extension-ip-route'}{'extension-ip-route'}={'ip-address'=>"$ip_address[$value]"};
$keyvals{'Response'}{'brocade-extension-ip-route'}{'extension-ip-route'}={'ip-prefix-length'=>"$ip_prefix_length[$value]"};
$keyvals{'Response'}{'brocade-extension-ip-route'}{'extension-ip-route'}={'ip-gateway'=>'*'};
}
print Dumper \%keyvals;
Each array value assign into hash value. $var1= {
'Response' => {
'extension-ip-route' => {
'status-flags' => 'U H L '
,
'ip-gateway' => '*',
'name' => '0/2',
'ip-address' => '192.168.20.11',
'dp-id' => '0',
'ip-prefix-length'=>'32'
}
}
};

Resources