Create, populate and access a multi-dimensional array in Perl - perl

I have the data structure (given below), can you please let me know how to populate and also to access the elements in the simplest form anytime I want. Which is the best way to implement, like Hash of Hashes or Array of Arrays or anything else ? There won't be too many elements in the array, the only problem is the its a multi-level kind of array
%Array = (
'Item0' => {
'Name' => 'Item0_Name',
'Attribs' => {
'Attr1' => {
'Name' => 'Attr1_Name',
'Num' => 'Attr1_Num'
},
'Attr2' => {
'Name' => 'Attr2_Name',
'Num' => 'Attr2_Num'
}
}
},
'Item1' => {
'Name' => 'Item1_Name',
'Attribs' => {
'Attr1' => {
'Name' => 'Attr1_Name',
'Num' => 'Attr1_Num'
},
'Attr2' => {
'Name' => 'Attr2_Name',
'Num' => 'Attr2_Num'
}
}
}
);

The official resource for this is the Perl Data Structure Cookbook (perldoc perldsc).
For the data shown, it seems that an array of hashrefs is sufficient since the keys shown in the OP are simply a stringified index. The same comment applies for 'Attribs':
my #array = (
{
'Name' => 'Item0_Name',
'Attribs' => [
{
'Name' => 'Attr1_Name',
'Num' => 'Attr1_Num'
},
{
'Name' => 'Attr2_Name',
'Num' => 'Attr2_Num'
}
],
},
{
'Name' => 'Item1_Name',
'Attribs' => [
{
'Name' => 'Attr1_Name',
'Num' => 'Attr1_Num'
},
{
'Name' => 'Attr2_Name',
'Num' => 'Attr2_Num'
}
],
},
);

Related

Converting hash to json format file [Perl]

So I created a function that creates a hash %data which looks as follows:
{
'10517' => {
'parent' => '10516',
'start' => 1545321095,
'end' => 1545321098,
'name' => 'A'
},
'10515' => {
'parent' => '10513',
'start' => 1545321091,
'end' => 1545321095,
'name' => 'B'
},
'10514' => {
'parent' => '10513',
'start' => 1545321091,
'end' => 1545321095,
'name' => 'C'
},
'10516' => {
'parent' => '10513',
'start' => 1545321091,
'end' => 1545321095,
'name' => 'D',
},
'10511' => {
'parent' => '#####',
'start' => 1545321090,
'end' => 1545321099,
'name' => 'E'
},
'10513' => {
'parent' => '10511',
'start' => 1545321091
'end' => 1545321097
'name' => 'F'
},
'10518' => {
'parent' => '10516',
'start' => 1545321094,
'end' => 1545321098,
'name' => 'G',
},
'10519' => {
'parent' => '10517',
'start' => 1545321096,
'end' => 1545321097,
'name' => 'H',
}
}
I would like to create a function which converts the data into the following output:
{
'children' : [
{
'id' : 10511,
'start' : 1545321090,
'end' : 1545321099,
'name' : 'E'
'children' : [
{
'id' : 10513,
'start' : 1545321091,
'end' : 1545321097,
'name' : 'F'
'children' : [
{
'id' : 10516,
'start' : 1545321091,
'end' : 1545321095,
'name' : 'D'
},
{
'id' : 10514,
'start' : 1545321091,
'end' : 1545321095,
'name' : 'C'
},
{
'id' : 10515,
'start' : 1545321091,
'end' : 1545321095,
'name' : 'B'
},
{
'id' : '10517',
'start' : 1545321095,
'end' : 1545321098,
'name' : 'A'
}
]
}
]
}
],
}
It is not the fully expected data (meaning I was too lazy to add the other ids into the nested format).
I would like to convert the hash %data to be contain a tree-type format as was showen in the example. The final goal is to have a nested data so each parent hash an array of each children, and each one of those children has an array of their own children (if they have of course), and so on.
How should I approch this problem? I'm looking for the cleanest and most effiecnt way possible. Also If possible, without any additional modules.
Just push the child elements into a children array in the parent:
use strict;
use warnings;
use Data::Dumper;
my $data =
{
'10517' => {
'parent' => '10516',
'start' => 1545321095,
'end' => 1545321098,
'name' => 'A'
},
'10515' => {
'parent' => '10513',
'start' => 1545321091,
'end' => 1545321095,
'name' => 'B'
},
'10514' => {
'parent' => '10513',
'start' => 1545321091,
'end' => 1545321095,
'name' => 'C'
},
'10516' => {
'parent' => '10513',
'start' => 1545321091,
'end' => 1545321095,
'name' => 'D',
},
'10511' => {
'parent' => '#####',
'start' => 1545321090,
'end' => 1545321099,
'name' => 'E'
},
'10513' => {
'parent' => '10511',
'start' => 1545321091,
'end' => 1545321097,
'name' => 'F'
},
'10518' => {
'parent' => '10516',
'start' => 1545321094,
'end' => 1545321098,
'name' => 'G',
},
'10519' => {
'parent' => '10517',
'start' => 1545321096,
'end' => 1545321097,
'name' => 'H',
}
};
my $root = [];
for my $id (keys %$data) {
my $entry = $data->{$id};
$entry->{id} = $id;
my $parent = $data->{$entry->{parent}};
unless ($parent){
push #$root, $entry
}
else{
push #{$parent->{children}},$entry;
}
}
print Dumper $root;
see
perldoc perldsc
for an introduction to nested data structures.

Accessing Specific OTRS Dynamic Field value via SOAP

How do I further access this dynamic field value? Upon using below dumper,
print Dumper( $Body->{$ResponseKey} );
The result is :
$VAR1 = {
'Ticket' => {
'Title' => 'TPLUS Service PIC',
'DynamicField' => [
{
'Value' => '43312',
'Name' => 'BugID'
},
{
'Value' => '6',
'Name' => 'OTRSMV'
},
{
'Value' => '6.13',
'Name' => 'OTRSPLV'
},
{
'Value' => 'Dev',
'Name' => 'OTRSUse'
},
{
'Value' => '2018-03-02 00:28:00',
'Name' => 'RefDate'
},
{
'Value' => '0',
'Name' => 'RefNumber'
},
{
'Value' => '',
'Name' => 'StartTime'
}
],
'StateType' => 'open',
'SLAID' => ''
}
};
How can I access the single value of DynamicField->RefDate ? Thanks
my $fields = $Body->{$ResponseKey}{Ticket}{DynamicField};
my ($ref_date) =
map $_->{Value},
grep $_->{Name} eq 'RefDate',
#$fields;
or
my %fields;
$fields{ $_->{Name} } = $fields{ $_->{Value} }
for #{ $Body->{$ResponseKey}{Ticket}{DynamicField} };
my $ref_date = $fields{RefDate};

Extracting specific elements from hash

my %hash = {
'student1' => {
'Name' => 'aaa',
'Age' => '20',
'Subjects' => ['Maths','Science']
},
'student2' => {
'Name' => 'bbb',
'Age' => '22',
'Subjects' => ['English','Science']
}
}
my $hashRef = \%hash;
how do i extract the second subject name from this using hashref ?
Your declaration of %hash is incorrect, do this instead:
my %hash = (
'student1' => {
'Name' => 'aaa',
'Age' => '20',
'Subjects' => ['Maths','Science']
},
'student2' => {
'Name' => 'bbb',
'Age' => '22',
'Subjects' => ['English','Science']
}
);
Note the parens instead og brace.
Then to get the second subject :
say $hashRef->{student1}{Subjects}[1];
Your code is wrong, { } creates a hashref and you are storing it in a hash. You should do:
my %hash = (
'student1' => {
'Name' => 'aaa',
'Age' => '20',
'Subjects' => ['Maths','Science']
},
'student2' => {
'Name' => 'bbb',
'Age' => '22',
'Subjects' => ['English','Science']
}
);
my $hashRef = \%hash;
or even better:
my $hashref = {
student1 => { ... },
student2 => { ... },
};
Then you can access with:
$hashRef->{student2}->{Subjects}[1]
Subjects are an array reference inside a hash inside a hash.
$hashRef->{student1}{Subjects}[1]
Also, do not use curly brackets to initilize a hash, they create an anonymous hash. Use round parentheses:
my %hash = ( ... );

Perl printing second level hash keys in a nested hash

How do I print all my second level hash keys (sig_qtr, date, range, etc.) given a hash like such:
my $xml = XMLin("./${spec_file}", ForceArray => ['range', 'constant', 'question', 'date', 'sig_yr', 'sig_qtr', 'sig_mth'], KeyAttr => {});
print Dumper $xml->{entities};
print dumper output of hash:
$VAR1 = {
'sig_qtr' => [
{
'name' => 'q1',
'label' => 'q1'
},
{
'name' => 'q4',
'label' => 'q4'
}
],
'date' => [
{
'name' => 'y2_mth',
'label' => 'pryr_mth_curr'
},
{
'name' => 'y3_pod6_qtr4',
'label' => 'curr_qtd4'
}
],
'range' => [
{
'name' => 'y0_jun',
'end' => '20100631',
'start' => '20100601'
},
{
'name' => 'y3_oct',
'end' => '20131031',
'start' => '20131001'
}
],
'constant' => [
{
'spec' => '99999999 and 99999999',
'name' => 'none_sixmth'
}
],
'sig_yr' => [
{
'name' => 'y1_sig',
'label' => 'ye11'
},
{
'name' => 'y3_sig',
'label' => 'ytd'
}
],
'sig_mth' => [
{
'name' => 'y3_nov',
'label' => 'nov12'
},
{
'name' => 'y3_oct',
'label' => 'oct13'
}
],
'question' => [
{
'name' => 'ltrq',
'label' => 'q9'
},
{
'name' => 'nextprod',
'label' => 'q12a'
}
],
'backfill' => {
'label' => 'bf_period'
},
'year' => {
'current' => '2013'
}
};
would be even better if keys are put into an array.
Thanks.
print "$_\n" for keys %{ $xml->entities };
To put them into an array,
my #keys = keys %{ $xml->entities };

perl how to use exists to check if hash is in array of hashes

i have two array of hashes: AH1 and AH2.
$AH1 = [
{
'id' => 123,
'name' => abc
},
{
'id' => 456,
'name' => def
},
{
'id' => 789,
'name' => ghi
},
{
'id' => 101112,
'name' => jkl
},
{
'id' => 1389,
'name' => mno
}
];
$AH2 = [
{
'id' => 123,
'name' => abc
},
{
'id' => 1389,
'name' => mno
},
{
'id' => 779,
'name' => ghi
}
];
how can i print hashes of AH1 that are in AH2 using Perl exists Function? or without having to iterate in the array.
exists locates by index, which are 0,1,2, and not 123,1389,779. exists can't help.
Furthermore, you must iterate over both array (one way or another) unless you switch one of the arrays to a hash.
$HH2 = {
123 => {
'id' => 123,
'name' => abc
},
1389 => {
'id' => 1389,
'name' => mno
},
779 => {
'id' => 779,
'name' => ghi
}
};
In fact, switching is the easiest way to solve this.
my %HH2 = map { $_->{id} => $_ } #$AH2;
for (#$AH1) {
print "$_->{id} in both\n"
if $HH2{ $_->{id} };
}
It's also quite efficient: You iterate over each array only once.