I'm working on a script and trying to get some values from an array stored in a hash. After searching on Google, searching for questions on SO (and there are some with similar titles but which have remained unsolved or solve problems a little bit different than mine), and after checking out the Data Structures Cookbook and trying everything reasonable to try, I've come to ask your help.
I have a hash, $action, and an array, $action->{'Events'}. Here's the output for print Dumper($action->{'Events'});:
$VAR1 = [{
'Muted' => 'something',
'Role' => 'something',
'Event' => 'something',
'Channel' => 'something',
'Talking' => 'something',
'UserNumber' => 'somenumber',
'CallerIDName' => 'somenumber',
'Conference' => 'somenumber',
'MarkedUser' => 'something',
'ActionID' => 'somenumber',
'CallerIDNum' => 'somenumber',
'Admin' => 'something'
}];
I need to get, for example, the value of $action->{'EVENTS'}->{'CallerIDName'}, but this syntax and many other won't work. I've even tried $action->{'EVENTS'}[6] and $action->{'EVENTS'}->[6] and so on.
It is Array of hashes, try this way:
$action->{'EVENTS'}[0]->{'CallerIDName'}
see perldsc for more detail.
Updated example like:
use strict;
use warnings;
use Data::Dumper;
my $action = {};
$action->{'Events'} = [{'Muted' => 'something',
'Role' => 'something',
'Event' => 'something',
'Channel' => 'something',
'Talking' => 'something',
'UserNumber' => 'somenumber',
'CallerIDName' => 'somenumber',
'Conference' => 'somenumber',
'MarkedUser' => 'something',
'ActionID' => 'somenumber',
'CallerIDNum' => 'somenumber',
'Admin' => 'something'}];
#push hash into the array of hashes
push(#{$action->{'Events'}},{'Muted' => 'something',
'Role' => 'something1',
'Event' => 'something1',
'Channel' => 'something1',
'Talking' => 'something1',
'UserNumber' => 'somenumber1',
'CallerIDName' => 'somenumber1',
'Conference' => 'somenumber1',
'MarkedUser' => 'something1',
'ActionID' => 'somenumber1',
'CallerIDNum' => 'somenumber1',
'Admin' => 'something1'} );
for(my $i=0; $i < #{$action->{'Events'}}; $i++){
print Dumper($action->{Events}[$i]); #print entire hash in array index $i
#print callerIDName key(any key) of each hash
print Dumper($action->{'Events'}[$i]->{'CallerIDName'});
}
The one you're missing is that the $action contains a reference to an array, so the next part must dereference the array. Then within that is a hash, and you need to dereference the hash. So it should look like this:
$action->{'EVENTS'}[0]{'CallerIDname'}
(note that the ->'s beyond the first are optional, so this is fine as well:
$action->{'EVENTS'}->[0]->{'CallerIDname'}
And does the exact same thing)
The [ ] on the outside indicate the hash is inside an array. So try:
$action->{Events}->[0]->{CallerIDName}
You can omit the -> between the {Events} and [0], but I prefer it for clarity. It doesn't make a difference here, but it does in other places. Compare:
#array = (1,2,3);
$arrayref = \#array;
print $arrayref[0]; # accesses non-existent array #arrayref
print $arrayref->[0]; # '1'
Related
I am fairly new in Perl, and having worked all my life with R, there are something that I can't really can wrap my mind around.
I have an array of hashes. In all of the hashes, the keys are the same ones, but the values are different. I want to get the number of the hash that has a specific value in it, because in that hash there is another value that I want (and varies among different samples).
I don't know if this is the way that I should be addressing it, but is the one I can think of. Here is a piece of the array:
$VAR16 = {
'harmonized_name' => 'geo_loc_name',
'attribute_name' => 'geo_loc_name',
'content' => 'not determined',
'display_name' => 'geographic location'}
$VAR17 = {
'harmonized_name' => 'env_package',
'attribute_name' => 'env_package',
'content' => 'missing',
'display_name' => 'environmental package'}
In this example, I would want the 'content' value of the hash that has 'harmonized_name' = env_package
You can use grep to filter all array elements which have 'harmonized_name' = env_package, and then check their values for content,
use strict;
use warnings;
my #AoH = (
{
'harmonized_name' => 'geo_loc_name',
'attribute_name' => 'geo_loc_name',
'content' => 'not determined',
'display_name' => 'geographic location'
},
{
'harmonized_name' => 'env_package',
'attribute_name' => 'env_package',
'content' => 'missing',
'display_name' => 'environmental package'
}
);
my #result = grep { $_->{harmonized_name} eq "env_package" } #AoH;
print $_->{content}, "\n" for #result;
output
missing
I'm trying to sort my AoH which looks like this:
$VAR1 = [
{
'Name' => 'John',
'Lastname' => 'Derp',
'Organization' => 'Finance',
'OfficeNR' => '23',
'ID' => '145'
},
{
'Name' => 'Kate',
'Lastname' => 'Herp',
'Organization' => 'HR',
'OfficeNR' => '78',
'ID' => '35'
},
{
'Name' => 'Jack',
'Lastname' => 'Serp',
'Organization' => 'Finance',
'OfficeNR' => '23',
'ID' => '98'
}
];
What I'm trying to do is to filter my output using keys from AoH, for example print out only those who have 'Organization' => 'Finance'.
I've tried to solve it using new array:
my #SortedAoH = sort { {Organization=>{'Finance'}} } #AoH;
But it doesn't work.
What you want is grep, not sort. You are getting the basic syntax of equivalence checking wrong as well.
Anyway, the filter is:
my #finance_orgs = grep { $_->{'Organization'} eq 'Finance' } #AoH;
The #finance_orgs variable will now only include the ones with Organization set to Finance.
Just an explanation of the pieces:
The $_ variable is the variable that gets assigned whenever the value is implied in a block, such as in grep or map or in a for loop without an explicitly named variable.
$_->{'Organization'} performs a hash lookup on the hash as it iterates through each entry in your array.
eq is the operator used to test for string equivalence (as opposed to == which tests for numeric equivalence).
Given the following anonymous array of hashes:
$AoH = [
{
'FORM_FIELD_ID' => '10353',
'VISIBLE_BY' => '10354',
'FIELD_LABEL' => 'ISINCIDENT',
'VALUE' => '',
'DEFAULT_FIELD_LABEL' => 'Yes No',
'FORM_ID' => '2113',
},
{
'FORM_FIELD_ID' => '10354',
'VISIBLE_BY' => '0',
'FIELD_LABEL' => 'CATEGORY',
'VALUE' => 'zOS Logical Security (RACF)',
'DEFAULT_FIELD_LABEL' => 'CATEGORY',
'FORM_ID' => '2113',
},
{
'FORM_FIELD_ID' => '10368',
'VISIBLE_BY' => '10354',
'FIELD_LABEL' => 'STARTDATE',
'VALUE' => '',
'DEFAULT_FIELD_LABEL' => 'REQTYPE',
'FORM_ID' => '2113',
}
];
How would I directly access the FIELD_LABEL value given that I knew the FORM_FIELD_ID is 10353?
I know I can loop through #$AoH and conditionally find $_->{FIELD_LABEL} based on $_->{FORM_FIELD_ID} == 10353, but is there anyway to directly access the wanted value if one of the other values in the same hash is known?
No, not unless you change your data structure. You could e.g. index the records by their form field id:
my %by_form_field_id = map { $_->{FORM_FIELD_ID} => $_ } #$AoH;
Then:
my $field_label = $by_form_field_id{10353}{FIELD_LABEL};
Without changing the data structure, you really have to grep:
my $field_label = (grep { $_->{FORM_FIELD_ID} == 10353 } #$AoH)[0]->{FIELD_LABEL};
You'd have to write a function loop through #array and examine the %hash or maybe use the builtin grep method:
say $_->{FIELD_LABEL} for (grep { $_->{FORM_FIELD_ID} == 10353 } #$AoH )
works. And so does this:
say %$_->{FIELD_LABEL} for (grep { $_->{FORM_FIELD_ID} == 10353 } #$AoH )
but it gives a Using a hash as a reference is deprecated warning (with pumpkin perl-5.16.3).
I have a hash whose keys is a string and key is array(the complication is that the array is defined in the square bracket), So my hash is like this..
model = {
'add' => [
{'name' => 'abc1', 'value' => 'def' },
{'name' => 'abc2', value => 'ghi'}
],
'remove' => [
{'name' => 'abc1', 'value' => 'def' },
{'name' => 'abc2', value => 'ghi'}
]
};
So what I am trying to achive is that when I try to iterate through the hashes of array
model->{add} as
print $_->{name} foreach(model->{add})
it doesnt work.
I guess this is because the array is in [] instead of ().
Considering the input cannot be changed. please let me know how to get through this...
$model = { 'add' => [ {'name' => 'abc1', 'value' => 'def' },
{'name' => 'abc2', 'value' => 'ghi'} ],
'remove' => [ {'name' => 'abc1', 'value' => 'def' },
{'name' => 'abc2', 'value' => 'ghi'} ] };
print $_->{name} foreach( #{ $model->{add} } );
You have a 3-level nested structure: A HashRef containing ArrayRefs containing HashRefs.
my $model = {
'add' => [
{
'name' => 'abc1',
'value' => 'def'
}, {
'name' => 'abc2',
value => 'ghi'
}
],
'remove' => [
{
'name' => 'abc1',
'value' => 'def'
}, {
'name' => 'abc2',
value => 'ghi'
}
]
};
To access those nested arrays and hashes, you need to dereference them, by adding % or # in front of it, depending on whether it is a hash or array.
my $arrayref = $model->{add};
foreach my $hashref (#$arrayref) {
print $hashref->{name}, "\n";
}
The statement:
print $_->{name} foreach(model->{add})
Does not work because model is a bareword, not a variable. If you have these two pragmas in your code:
use strict;
use warnings;
You will not be able to make mistakes like this. warnings will tell you:
Unquoted string "model" may clash with future reserved word at ...
Name "main::model" used only once: possible typo at ...
Use of uninitialized value in print at ...
And strict will tell you:
Can't use bareword ("model") as a HASH ref while "strict refs" in use at ...
However, if you do not have those two pragmas enabled, Perl will happily print the empty string and be silent about the whole thing. Which makes the mistake rather hard to detect.
The correct way to handle this is to grab the correct scalar value from the hash, and dereference it using the correct sigil. If you look at the key 'add':
'add' => [
You'll see that it has an array reference stored in it, which means the sigil to use is #. You'll need support curly braces to disambiguate the references. Also, you have to refer to your variable as $model.
print $_->{name} for #{ $model->{add} };
Which is the same as
my $adds = $model->{add};
print $_->{name} for #$adds;
First and foremost use use strict; use warnings;
The scalar model should be written as
my $model = { 'add' => [ {'name' => 'abc1', 'value' => 'def' }, {'name' => 'abc2', value => 'ghi'} ], 'remove' => [ {'name' => 'abc1', 'value' => 'def' }, {'name' => 'abc2', value => 'ghi'} ] };
and
print $_->{name} foreach( ( #{ $model->{ add } } ) );
How do you get the size of the following array of hashes?
I thought this would do it, but it did not work...
print Dumper scalar $item->{'detail'};
$VAR1 = [
{ 'content' => undef, 'name' => 'entree', 'url_name' => 'entree' },
{ 'content' => undef, 'name' => 'dessert', 'url_name' => 'desert' },
{ 'content' => undef, 'name' => 'drink', 'url_name' => 'drink' }
];
Or how can I print all the url_name (entree, desert, drink) in the array of hashes without knowing the size?
You have an array reference. To get the size of the referenced array, first dereference the reference:
print scalar #{$item->{'detail'}};
And to list the URLs:
my $v = [
{ 'content' => undef, 'name' => 'entree', 'url_name' => 'entree' },
{ 'content' => undef, 'name' => 'dessert', 'url_name' => 'desert' },
{ 'content' => undef, 'name' => 'drink', 'url_name' => 'drink' }
]; # or $v = $item->{'detail'};
foreach my $h (#$v) {
print $h->{url_name}, "\n";
}
I'm not sure why you think you need the array size in order to print the url_name values. Nonetheless, here's how it works.
use strict;
use warnings;
use Data::Dumper;
my $v = [ # note that this is a scalar value
{ 'content' => undef, 'name' => 'entree', 'url_name' => 'entree' },
{ 'content' => undef, 'name' => 'dessert', 'url_name' => 'desert' },
{ 'content' => undef, 'name' => 'drink', 'url_name' => 'drink' }
];
my $item = { detail => $v }; # recreate your structure $item->{detail}
my $size = #$v; # this is how its done with $v
my $size2 = #{ $item->{detail} }; # and with your original structure
my #x = map $_->{url_name}, #$v; # extract url_name values
print Dumper \#x;
As you see, $item->{detail} and $v are identical. When you feed this scalar value directly (through the scalar function, which does nothing in this case) to Dumper, you get the printed value seen in $v above. All that scalar does is change the context used with print and enforce a scalar context rather than list context. We can do the same thing by using scalar assignment ($size and $size2).
When using the original structure, you need to use the #{ } brackets to clarify for perl that what is inside them is an array ref.
As you see, extracting the values is easily done with a map statement. It acts as a loop, iterating over all the values in #$v (or #{ $item->{detail} }), returning for each value the statement $_->{url_name}.