searching a perl hash for a value - arrays

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

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

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

PHP Display Array with Array_Slice

$array = array(
'name' => 'john',
'age' => '25',
'birthday' => '02-03-1988',
'gender' => 'male',
'telephone' => '98676878',
'location' => 'Australia'
);
$array_slice = array_slice($array, 0, 3);
foreach($array_slice as $key => $val) {
if($key !== 'age') {
echo $key.' => '.$val.'<br>';
}
}
Output:
name => john
birthday => 02-03-1988
How to display 3 values of array?
So, I want output to be like this:
name => john
birthday => 02-03-1988
gender => male
I am very beginner in programmer, thanks for help.
Update: new solution after exchanging some comments below
You must filter the array and get the result in a new array. Then you display the content of the second array.
To filter your original array, use either array_intersect_key or array_filter functions.

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

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

Perl- Iterating through an array of hashes with square brackets

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

Resources