Array in value of hash perl - arrays

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

Related

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"]

access hash member of type array within array of hashes

I have an array of anonymous hashes like this:
my #arrayOfHashes=(
{
name => 'foo',
value => ['one', 'two']
},
{
name => 'bar',
value => ['two', 'three']
}
);
I'm trying to iterate over the array and access the array within each hash:
foreach (#arrayOfHashes) {
print $_->{'value'} # ARRAY(0x88489f4)
}
The value that is printed above is not what I want... I want to use that array so it works like this:
print qw(one two) # onetwo
But, when I use qw like this:
my #arrayOfHashes=(
{
name => 'foo',
qw(one two)
},
{
name => 'bar',
qw(three four)
}
);
I get this error message at runtime (I am using strict mode):
Odd number of elements in anonymous hash at ...
How do I reference the "value" array within the foreach block?
So you have a reference to an array you want to dereference. The equivalent of #array for when you have a reference is #{ $ref }, so
print("#array\n");
print(join(', ', #array), "\n");
would be
print("#{ $_->{value} }\n");
print(join(', ', #{ $_->{value} }), "\n");
References:
Mini-Tutorial: Dereferencing Syntax
References quick reference
perlref
perlreftut
perldsc
perllol

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.

How do I reference a Perl hash in an array in a hash?

This is the code snippet I am working with:
my %photo_details = (
'black_cat' => (
('size' => '1600x1200', 'position' => -25),
('size' => '1280x1024', 'position' => 25),
('size' => '800x600', 'position' => 0),
),
'race_car' => (
('size' => '1600x1200', 'position' => 10),
('size' => '800x600', 'position' => 5),
),
);
my $photo = 'black_cat';
foreach my $photo_detail ($photo_details{$photo})
{
my $size = $photo_detail{'size'};
my $position = $photo_detail{'position'};
print ("size = $size, position = $position\n");
}
What I am expecting to get is:
size = 1600x1200, position = -25
size = 1280x1024, position = 25
size = 800x600, position = 0
What I do get is:
Use of uninitialized value $size in concatenation (.) or string at C:\Test.pl line 23.
Use of uninitialized value $position in concatenation (.) or string at C:\Test.pl line 23.
size = , position =
The foreach statement is clearly wrong as not only are there no values for $size and $position, it has only gone through the loop once instead of three times. I have tried all sorts of variants of variable prefixes and found none that work.
What am I doing wrong?
Here is some updated code, with an explanation below:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my %photo_details = (
'black_cat' => [
{'size' => '1600x1200', 'position' => -25},
{'size' => '1280x1024', 'position' => 25},
{'size' => '800x600', 'position' => 0},
],
'race_car' => [
{'size' => '1600x1200', 'position' => 10},
{'size' => '800x600', 'position' => 5},
],
);
print Dumper( %photo_details );
foreach my $name ( keys %photo_details ) {
foreach my $photo_detail ( #{ $photo_details{$name} } ) {
my $size = $photo_detail->{'size'};
my $position = $photo_detail->{'position'};
print Dumper( $photo_details{$photo} );
print ("size = $size, position = $position\n");
}
}
I've replaced some of your parentheses with square and curly brackets. In Perl, square brackets give you a reference to an anonymous array, and curly brackets denote a reference to an anonymous hash. These are called anonymous because there's no explicit variable name for the anonymous array or hash.
As Perl data structures make you store a reference to a hash rather than the actual hash, you need these to construct the references. You can do this in two steps like this:
my #array = ( 1, 2, 3 );
my $array_ref = \#array;
my %hash = ( 'one' => 1, 'two' => 2, 'three' => 3 );
my $hash_ref = \%hash_ref;
To get data out of $array_ref and $hash_ref, you need the -> operator:
print $array_ref->[0], "\n";
print $hash_ref->{one}, "\n";
You don't need the quotes inside of the {} when referencing a hash key, although some people consider quotes on a hash key to be good practice.
I added an example of iteration over the entire data structure as an example rather than just looking at one reference. Here's the first line:
foreach my $name ( keys %photo_details ) {
The keys method returns all of the keys in a hash, so that you can get them in order. The next line iterates over all of the photo_detail hashrefs in %photo_details:
foreach my $photo_detail ( #{ $photo_details{$photo} } ) {
The #{ $photo_details{$photo} } de-references the reference $photo_details{$photo} into an array, which you can iterate over it with foreach.
The last thing that I added is a call to Data::Dumper, a very useful module distributed with Perl that prints out data structures for you. This is very handy when building up data structures like this, as is its closely related cousin Data::Dumper::Simple. This module is unfortunately not distributed with Perl, but I prefer its output as it includes variable names.
For some further reading about how to build up complex data structures using references, check out perlreftut.
First of all, always start every script or module with:
use strict;
use warnings;
You will get more warning messages and sooner, which greatly helps debugging.
I cannot duplicate your error: when I put that code into a file and run it with no additional flags, I get: size = , position =. There is no $size variable in the code you printed, so the error message does not match.
Nevertheless, you are declaring your data structures incorrectly. Hashes and arrays can
only contain scalar values, not lists: so if you want to nest an array or
a hash, you need to make it a reference. See perldoc perldata, perldoc perldsc
and perldoc perlreftut for more about data structures and references.
my %photo_details = (
black_cat => [
{ size => '1600x1200', position => -25 },
{ size => '1280x1024', position => 25 },
{ size => '800x600', position => 0 },
],
race_car => [
{ size => '1600x1200', position => 10 },
{ size => '800x600', position => 5 },
],
);
foreach my $photo_detail (#{$photo_details{black_cat}})
{
my $size = $photo_detail->{size};
my $position = $photo_detail->{position};
print ("size = $size, position = $position\n");
}
There's really only one thing you have to worry about, and that's the top level of the data structure. After that, you just use the right indexing syntax for each level:
If you have a regular hash, you access the key that you want then line up the additional indices for each level after it:
%regular_hash = ...;
$regular_hash{$key}[$index]{$key2};
If you have a reference, you do almost the same thing, but you have to start off with the initial dereference with an arrow, ->, after the top-level reference. After that it's the same indexing sequence:
$hash_ref = ...;
$hash_ref->{$key}[$index]{$key2};
For all of the details, see Intermediate Perl where we explain reference syntax.

Resources