Directly access value based on another value in anonymous array of hashes - arrays

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).

Related

Ruby Search Array of Hashes and Arrays

I have an array of hashes which also include an array:
machines = [{ 'name' => 'ldapserver1', 'ip' => '10.199.0.10',
'role' => ['server', 'initial'] },
{ 'name' => 'ldapserver2', 'ip' => '10.199.0.11',
'role' => ['server', 'secondary'] },
{ 'name' => 'ldapclient1', 'ip' => '10.199.0.12',
'role' => 'client' },
{ 'name' => 'ldapclient2', 'ip' => '10.199.0.13',
'role' => 'client' }]
I want to search thru it to get the machine with a matching role.
I can use this to get machines with the client role:
results = #machines.select { |machine| machine['role'] == 'client' }
[{"name"=>"ldapclient1", "ip"=>"10.199.0.12", "role"=>"client"}, {"name"=>"ldapclient2", "ip"=>"10.199.0.13", "role"=>"client"}]
But when I try to search the array of roles this breaks:
results = machines.select { |machine| machine['role'] == 'server' }
[]
How can I search through the role arrays to find matches for my machines?
This is a perfect use-case for Enumerable#grep:
machines.reject { |m| [*m['role']].grep('server').empty? }
Here a splat is used to produce an array from both Array instance and the String instance.
As per your code the roles can be string or array so safe to check using following
results = machines.select { |machine| Array(machine['role']).include?('server') }
Update: using Array, this method tries to create array by calling to_ary, then to_a on its argument.
That is because 'role' can be a string or an array.
Using #include? will match part of a string if it's a string. Or fully match a string inside an array.
Try:
results = machines.select { |machine| machine['role'].include?('server') }
Or more robust
results = machines.select do |machine|
r = machine['role']
if r.is_a? String
r == 'server'
else
r.include?('server')
end
end

Get the hash number

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

Perl: Filter AoH output

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).

searching a perl hash for a value

I'm reading in an xml file using XMLin and it gives me this...
'Date' => '01Jan2013',
'Total' => 3,
'Details' => {
'Detail' => [
{
'Name' => 'Bill',
'ID' => '123',
'IP' => '255.255.255.1'
},
{
'Name' => 'Ted',
'ID' => '456',
'IP' => '255.255.255.2'
},
{
'Name' => 'Fred',
'ID' => '789',
'IP' => '255.255.255.3'
},
]
}
I'm trying to search the {Detail}[Name] values for a particular name. So I want to search for Fred to get his name and IP address.
foreach my $ruleline ($pricesettings->{Details}{Detail}['Name']){
if ($pricesettings->{Details}{Detail}["Name"] eq "Fred") {
print "Found you\n";
}
else {
print "Not found\n";
}
}
But even if I print Dumper($pricesettings->{Details}{Detail}['Name']) within the for loop it only prints the first record entries for Bill.
Ideally I want to see output like
Name => 'Bill'<br>
Name => 'Ted'<br>
Name => 'Fred'<br>
Then if Fred is found I want to get Fred's IP address or ID. I have no problem finding or comparing the value 'Date' or 'Total' for example, but each grouping under 'Detail' is causing me a problem.
your code snippet is slightly off. instead, try
foreach my $ruleline (#{$pricesettings->{Details}{Detail}}){
if ( $ruleline->{"Name"} eq "Fred") {
print "Found you\n";
}
else {
print "Not found\n";
}
}
In order to arrive at the output you actually aim at, try the following:
foreach my $ruleline (#{$pricesettings->{Details}{Detail}}){
print "Name -> '$$ruleline{Name}'" ;
if ( $$ruleline{Name} eq "Fred") {
print "; ID -> '$$ruleline{ID}', IP -> '$$ruleline{IP}';" ;
}
print "\n";
}
technical explanation:
in your original code you've mixed up arrays and hashes. for complex data structures of the kind you employ consider switching to an oo programming style, maybe using Moose (though that might be overkill).

I don't understand this Perl Syntax, has anyone got any idea?

I have got this part from a Perl plugin. I don't understand what it does. Is it an array of associative arrays? If so, then shouldn't it be started with #? Can anyone shed some light on this issue?
my $arguments =
[ { 'name' => "process_exp",
'desc' => "{BasePlugin.process_exp}",
'type' => "regexp",
'deft' => &get_default_process_exp(),
'reqd' => "no" },
{ 'name' => "assoc_images",
'desc' => "{MP4Plugin.assoc_images}",
'type' => "flag",
'deft' => "",
'reqd' => "no" },
{ 'name' => "applet_metadata",
'desc' => "{MP4Plugin.applet_metadata}",
'type' => "flag",
'deft' => "" },
{ 'name' => "metadata_fields",
'desc' => "{MP4Plugin.metadata_fields}",
'type' => "string",
'deft' => "Title,Artist,Genre" },
{ 'name' => "file_rename_method",
'desc' => "{BasePlugin.file_rename_method}",
'type' => "enum",
'deft' => &get_default_file_rename_method(), # by default rename imported files and assoc files using this encoding
'list' => $BasePlugin::file_rename_method_list,
'reqd' => "no"
} ];
As Bwmat said it's a reference to an Array of Hash references. Read
$ man perlref
or
$ man perlreftut # this is a bit more straightforward
for if you want to know more about references.
By the way in fiew words in Perl you can do:
#array = ( 1, 2 ); # declare an array
$array_reference = \#array; # take the reference to that array
$array_reference->[0] = 2; # overwrite 1st position of #array
$numbers = [ 3, 4 ]; # this is another valid array ref declaration. Note [ ] instead of ( )
the same thing happens with hashes.
By the way in fiew words in Perl you can do:
%hash = ( foo => 1, bar => 2 );
$hash_reference = \%hash;
$hash_reference->{foo} = 2;
$langs = { perl => 'cool', php => 'ugly' }; # this is another valid hash ref declaration. Note { } instead of ( )
And... yes, you can dereference these references.
%{ $hash_reference }
will be treated as it was a hash, so if you want to print the keys of $langs above, you can do:
print $_, "\n" foreach ( keys %{ $langs } );
To dereference an array ref use #{ } instead of %{ }. Even sub can be dereferenced.
sub foo
{
print "hello world\n";
}
my %hash = ( call => \&foo );
&{ $hash{call} }; # this allows you to call the sub foo
$arguments is an array reference (a reference/pointer to an array)
You initialize arrays with () and array references with []
my #array = ( 1, 2, 3 );
my $array_ref = [ 1, 2, 3 ];
You can create a reference with \
my $other_array_ref = \#array;
When you use an array reference you will then to dereference it when using:
for my $element ( #{$array_ref} )
or
print ${$array_ref}[0];
See man perlref
Back to your question: $arguments is a reference to an array of hash references (initialized with {})
Looks like a hash of hashes reference.
you may need to dereference like
%newhash = %{$arguments}
and print the data as
print $newhash{'name'}

Resources