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

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.

Related

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

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

Extracting an array of non=sibling hash values from a nested data structure in perl

This is my data structure created by Data::Dumper->Dumper:
$VAR1 = {
'name' => 'genomic',
'class' => [
{
'reference' => [
{
'name' => 'chromosome',
'referenced-type' => 'Chromosome'
},
{
'name' => 'chromosomeLocation',
'referenced-type' => 'Location'
},
{
'name' => 'sequence',
'referenced-type' => 'Sequence'
},
{
'name' => 'sequenceOntologyTerm',
'referenced-type' => 'SOTerm'
}
],
}
],
};
(trimmed for clarity)
I would like to return a reference to an array of each name value under reference in a single line.
Currently I have
$class->[0]{reference}[0..3]{name}
but no avail.
Also this example has four sibling-hashes with indexes 0..3, how can I represent the whole array independent of the number of elements?
There isn't an easy syntax to do that, unfortunately. You'll have to use map:
my $array_ref = [
map { $_->{name} } #{ $class->[0]{reference} }
];
Then, if you dump out $array_ref, you'll see it contains:
$array_ref = [
'chromosome',
'chromosomeLocation',
'sequence',
'sequenceOntologyTerm'
];
If you need references to the original strings (not copies), you just need a backslash before $_ (so it'd be \$_->{name} inside the map).
$class->[0]{reference} is an array reference, so you have to dereference it with #{}:
#{$class->[0]{reference}}
Is the 'whole array', you can then use slice syntax on the end to get a part of it:
#{$class->[0]{reference}}[0..3]
From there you're working with an array of hashrefs, so you'll have to iterate over it with for or map.

How to declare AoHoAoH?

I have this output from Dumper
'group' => {
'1104' => {
'a' => 1
},
'52202' => {
'b' => 1,
'c' => 1
},
'52201' => {
'c' => 1
},
'52200' => {
'c' => 1
}
},
which I assume is an Array of Hashes of Arrays of Hashes?
I would like to declare this structure my self.
Is there a way to do this, so next time I see such a complex structure, I can do that in no time? =)
Your output is a hash of hashes of hashes, with the first hash only containing a single element. The {} mark a hash reference, so you'd repeat your data structure thus, where the resulting $hohoh is a refrence to a HoHoH.
my $hohoh = {
'group' => {
'1104' => {
'a' => 1
},
'52202' => {
'b' => 1,
'c' => 1
},
'52201' => {
'c' => 1
},
'52200' => {
'c' => 1
}
},
};
print $hohoh->{group}{1104}{a}; # -> 1
I recommend reading the Perl Datastructures Cookbook.
Since the types of variables, and of hash values, can change in Perl, there isn't any way to "declare" a three-level hash the way you're probably thinking. You can instantiate an empty hashref into each key as it's created, which is a similar idea:
# First pass
my $data = {};
# Later...
$data->{group} = {};
# Still later...
$data->{group}->{1104} = {};
# Finally...
$data->{group}->{1104}->{a} = 1;
But you could just as easily simply fill in the data as you obtain it, allowing autovivification to do its thing:
my $data;
# Fill one piece of data... Perl creates all three hash levels now.
$data->{group}->{1104}->{a} = 1;
# Fill another piece of data, this one has two values in the "bottom" hash.
$data->{group}->{52202} = { b => 1, c => 2};
But there is no way (in plain Perl) to "enforce" that the values for any particular key contain hashes rather than strings or subroutine references, which is usually what is intended by declaration in languages with C-like type systems.

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