Converting hash to json format file [Perl] - 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.

Related

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

Convert multilevel hash in simple hash in perl

I have a hash that is multilevel hash i want to convert that into single level .But i am not able to do that
Actual Hash:
'MainSlab' => {
'A1' => {
'Slab' => {
'49_168' => {
'Amt' => '3000',
'Start' => '49',
'End' => '168'
},
'169_720' => {
'Amt' => '3000',
'Start' => '169',
'End' => '720'
},
'2_48' => {
'Amt' => '3000',
'Start' => '2',
'End' => '48'
},
'721_-' => {
'Amt' => '3000',
'Start' => '721',
'End' => '-'
}
}
},
'A2' => {
'Slab' => {
'49_168' => {
'Amt' => '3000',
'Start' => '49',
'End' => '168'
},
'169_720' => {
'Amt' => '4000',
'Start' => '169',
'End' => '720'
},
'2_48' => {
'Amt' => '5000',
'Start' => '2',
'End' => '48'
},
'721_-' => {
'Amt' => '3000',
'Start' => '721',
'End' => '-'
}
}
}
}
I want to convert that into simple and single level hash like this :
slab =>{
"49_168"=>{"A1"=> "3000","A2"=>"3000"},
"169_720"=>{"A1"=>"4000","A2"=>"4000"},
"2_48"=>{"A1"=>"5000","A2"=>"5000"},
"721_"=>{"A1"=>"3000","A2"=>"3000"}
}
Please help me to do this how can we do this
Assuming
my %hash = (
'MainSlab' => {
'A1' => {
'Slab' => {
'49_168' => {
'Amt' => '3000',
'Start' => '49',
'End' => '168'
},
'A2' => ...
);
Then:
my $hashref = $hash{'MainSlab'};
my $new_hashref = {};
foreach my $ax (keys %$hashref) {
foreach my $k (keys %{$hashref->{$ax}{'Slab'}}) {
$new_hashref->{$k}{$ax} = $hashref->{$ax}{'Slab'}{$k}{'Amt'};
}
}
my %new_hash = (slab => $new_hashref);
Will produce:
$new_hash = ( 'slab' => {
'49_168' => {
'A1' => '3000',
'A2' => '3000'
},
'169_720' => {
'A1' => '3000',
'A2' => '4000'
...
);
use Data::Dumper qw();
## actual hash $h1
my $h1 = { 'MainSlab' => { 'A1' => { 'Slab' => { '49_168' => { 'Amt' => '3000', 'Start' => '49', 'End' => '168' }, '169_720' => { 'Amt' => '3000', 'Start' => '169', 'End' => '720' }, '2_48' => { 'Amt' => '3000', 'Start' => '2', 'End' => '48' }, '721_-' => { 'Amt' => '3000', 'Start' => '721', 'End' => '-' } } }, 'A2' => { 'Slab' => { '49_168' => { 'Amt' => '3000', 'Start' => '49', 'End' => '168' }, '169_720' => { 'Amt' => '4000', 'Start' => '169', 'End' => '720' }, '2_48' => { 'Amt' => '5000', 'Start' => '2', 'End' => '48' }, '721_-' => { 'Amt' => '3000', 'Start' => '721', 'End' => '-' } } } } };
## transform to $h2
my #l2 = keys(%{$h1->{'MainSlab'}});
my #l1 = keys(%{$h1->{'MainSlab'}->{$l2[0]}->{'Slab'}});
my $h2 = {};
foreach my $l1 (#l1) {
my $inner = {};
foreach my $l2 (#l2) {
$inner->{$l2} = $h1->{'MainSlab'}->{$l2}->{'Slab'}->{$l1}->{'Amt'};
} ## end foreach
$h2->{'slab'}->{$l1} = $inner;
} ## end foreach
## print result
print(Data::Dumper->Dump([$h2],['$h2']));
Output:
$h2 = {
'slab' => {
'49_168' => {
'A1' => '3000',
'A2' => '3000'
},
'169_720' => {
'A1' => '3000',
'A2' => '4000'
},
'2_48' => {
'A1' => '3000',
'A2' => '5000'
},
'721_-' => {
'A1' => '3000',
'A2' => '3000'
}
}
};

Extracting data from a multi-level hash

I am getting the data structure below as a response from a web service call.
my $triggers1 = $zabbix->raw('trigger','get', $options1);
print Dumper($triggers1);
Output
$VAR1 = {
'10305122' => {
'hosts' => [
{
'name' => 'pc4b12cf254444',
'maintenance_type' => '0',
'hostid' => '19295'
}
],
'priority' => '1',
'status' => '0',
'dependencies' => [],
'templateid' => '9892568',
'comments' => '',
'state' => '0',
'triggerid' => '10305122',
'expression' => '{14127122}=0',
'error' => '',
'url' => '',
'flags' => '0',
'value' => '0',
}
324234' => {
'hosts' => [
{
'name' => 'pc45657ba34gy0423',
'maintenance_type' => '0',
'hostid' => '19439'
}
],
'priority' => '1',
'status' => '0',
'dependencies' => [],
'templateid' => '9896452',
'comments' => '',
'state' => '0',
'triggerid' => '10324234',
'expression' => '{14167689}=0',
'error' => '',
'url' => '',
'flags' => '0',
'value' => '0',
'value_flags' => '0',
'lastchange' => '1420266068',
'type' => '0'
};
etc
There are multiple similar records
From this output, I want to print the values of 'name' and 'value'.
How do I print this using Perl?
How about:
my $triggers1 = {
'10305122' => {
'hosts' => [
{
'name' => 'pc4b12cf254444',
'maintenance_type' => '0',
'hostid' => '19295'
}
],
'priority' => '1',
'status' => '0',
'dependencies' => [],
'templateid' => '9892568',
'comments' => '',
'state' => '0',
'triggerid' => '10305122',
'expression' => '{14127122}=0',
'error' => '',
'url' => '',
'flags' => '0',
'value' => '0',
},
324234 => {
'hosts' => [
{
'name' => 'pc45657ba34gy0423',
'maintenance_type' => '0',
'hostid' => '19439'
}
],
'priority' => '1',
'status' => '0',
'dependencies' => [],
'templateid' => '9896452',
'comments' => '',
'state' => '0',
'triggerid' => '10324234',
'expression' => '{14167689}=0',
'error' => '',
'url' => '',
'flags' => '0',
'value' => '0',
'value_flags' => '0',
'lastchange' => '1420266068',
'type' => '0'
}
};
Code disconnected from data for readability:
foreach my $k (keys %$triggers1) {
print "key=$k";
foreach my $h (#{$triggers1->{$k}{hosts}}) {
print "\nname=",$h->{name} // 'not defined';
// use this ^^ to avoid Use of uninitialized value in print at
}
print "\nvalue=",$triggers1->{$k}{value} // 'not defined',"\n";
}
Output:
key=324234
name=pc45657ba34gy0423
value=0
key=10305122
name=pc4b12cf254444
value=0

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

Create, populate and access a multi-dimensional array in 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'
}
],
},
);