Perl dynamic multidimensional array [duplicate] - arrays

This question already has answers here:
Push to array reference
(4 answers)
Closed 8 years ago.
In my Perl Programm, I used for testing the following static array definition:
my %data = (
56 => [
{ 'Titel' => 'Test 1',
'Subtitel' => 'Untertest 1',
'Beginn' => '00:05',
'Ende' => '00:50'
},
{ 'Titel' => 'Test 2',
'Subtitel' => 'Untertest 2',
'Beginn' => '00:50',
'Ende' => '01:40'
}
],
58 => [
{ 'Titel' => 'Test 3',
'Subtitel' => 'Untertest 3',
'Beginn' => '00:10',
'Ende' => '01:50'
}
],
51 => [
{ 'Titel' => 'Test 4',
'Subtitel' => 'Untertest 4',
'Beginn' => '00:05',
'Ende' => '00:20'
},
{ 'Titel' => 'Test 5',
'Subtitel' => 'Untertest 5',
'Beginn' => '00:20',
'Ende' => '00:40'
},
{ 'Titel' => 'Test 6',
'Subtitel' => 'Untertest 6',
'Beginn' => '00:40',
'Ende' => '01:05'
}
],
);
Now I like to change it, to get data from a database. My select returns 5 values: an id (like 56, 58 or 51 in my example) and the values for each Titel, Subtitel, Beginn and Ende.
How can I build the same array construct like in my static example?
Thanks in advance! Best regards
Daniel

Assuming you want it at the end, you need to push your hashref into the arrayref stored at $data{$id}:
push #{ $data{$id} }, {
Titel => $titel,
Subtitel => $subtitel,
Beginn => $beginn,
Ende => $ende,
};

Could be something like this. Sorry, it's been a while since I've done perl.
#!/usr/bin/perl
use Data::Dumper;
sub dataset2struc {
my $result = {};
foreach my $row (#_) {
my $id = $row->{'id'};
my $recref = $result->{$id} || ();
my #rec = #{$recref};
delete $row->{'id'};
push(\#rec, $row);
$result->{$id} = \#rec;
}
return $result;
}
my #dataset = ({"id" => 1, "a" => "b"}, {"id" => 2, "a" => "c"}, {"id" => 2, "a" => "d"});
print Dumper(dataset2struc(#dataset));

Related

Add array on the key of another array in laravel

I'm working in Laravel. I have two arrays, and I want to insert the second array as a value in the first. For example, given
$firstArray = [
'id' => 1,
'propery_name' => 'Test Property'
];
$secondArray = [
'id' => 2,
'user_name' => 'john'
];
, I want to produce an equivalent of
$resultArray = [
'id' => 1,
'propery_name' => 'Test Property',
'userData' => [
'id' => 2,
'user_name' => 'john'
]
];
How can I achieve that?
$resultArray = $firstArray;
$resultArray['userData'] = $secondArray;
Try this:
$firstArray = ['id'=>1,'propery_name'=>'Test Property'];
$secondArray = ['id'=>2,'user_name'=>'john'];
$resultArray = ['property' => $firstArray, 'userData' => $secondArray];
Your newly created array should give you this:
{{ $resultArray['userData']['user_name'] }} = John
{{ $resultArray['property']['propery_name'] }} = Test Property
$firstArray['userData'] = $secondArray;
return $firstArray;
//result
$resultArray = [
'id' => 1,
'propery_name' => 'Test Property',
'userData' => [
'id' => 2,
'user_name' => 'john'
]
];
You can use Laravel collection class for this. Push function is best way to add values in array. https://laravel.com/docs/5.5/collections#method-put
In your case,
$firstArray = [
'id' => 1,
'propery_name' => 'Test Property'
];
$secondArray = [
'id' => 2,
'user_name' => 'john'
];
$collection = collect($firstArray);
$collection->put('userData', $secondArray);
$collection->all();
Output:
['id' => 1,
'propery_name' => 'Test Property',
'userData' => [
'id' => 2,
'user_name' => 'john'
]
];

How to repeat the cellmerging in XLSX with openTBS?

Let me try to describe the problem in words. I have a headline in my array which should be centered in two merged cells. When opentbs is looping throug my array, only the first headline is in a merged cell, for all upcoming headlines the cellmerging gets lost.
The Array is similar to this:
$data = [
'name' => 'district one',
'streets' => [
[
'name' => 'first street',
'description' => 'first text',
],
[
'name' => 'second street',
'description' => 'second text',
]
],
'name' => 'district two',
'streets' => [
[
'name' => 'third street',
'description' => 'third text',
],
[
'name' => 'fourth street',
'description' => 'fourth text',
]
],
]
The cell structure i want to reach is like this:
Cellstructure
and this is the code of template:
[data;block=begin;sub1=streets]
[data.name;block=tbs.row]
[data_sub1;block=begin]
[data_sub1.name] [data_sub1.description]
[data_sub1;block=end]
[data;block=end]
here is the templatecode and the result in one img:
templatecode an result
How to repeat the cellmerging with openTBS?

how to add multiple values from multiple hashes with same key (perl)

Hello people im trying to add multiple values from multiple hashes with same key.
And this is the result of scheme that I want acomplish.
HASH1 => {
'2016-07-01' => { 'val1' => '7', 'val2' => '9', },
'2016-07-02' => { 'val1' => '10', 'val2' => '6', } }
HASH2 => {
'2016-07-01' => { 'val1' => '8', 'val2' => '4', },
'2016-07-03' => { 'val1' => '3', 'val2' => '2', } }
HASH3 => {
'2016-07-01' => { 'val1' => '6', 'val2' => '5', },
'2016-07-02' => { 'val1' => '1', 'val2' => '2', },
'2016-07-04' => { 'val1' => '4', 'val2' => '2', } }
OUTPUT HASH => {
'2016-07-01' => { 'val1' => '21', 'val2' => '18', },
'2016-07-02' => { 'val1' => '11', 'val2' => '8', },
'2016-07-03' => { 'val1' => '3', 'val2' => '2', },
'2016-07-04' => { 'val1' => '4', 'val2' => '2', }, }
Im trying pushing duplicate keys to an array to identify each one, then add values.
This i'm trying is for compare 2 hashes, but i want make it for multiple hashes.
my #common = ();
foreach (keys %HASH1) {
push(#common, $_) if exists $HASH2{$_};
}
foreach my $DUP_KEY (#common){
my $v1 = $HASH1{$DUP_KEY}{'val1'} + $HASH2{$DUP_KEY}{'val1'};
my $v2 = $HASH1{$DUP_KEY}{'val2'} + $HASH2{$DUP_KEY}{'val2'};
$HASH1{$DUP_KEY}{'val1'} = $v1;
$HASH1{$DUP_KEY}{'val2'} = $v2;
}
my %OUT_HASH = (%HASH1, %HASH2);
foreach my $key (keys %OUT_HASH) {push(#ARR, $key);}
foreach (sort #ARR) {push(#ARR_CLEAN, $_);
}
but the result is not as expected, because im getting only the duplicates keys only.
someone would be so kind as to help me? thank you!
To sum up the hashes of hashes, loop over all the hashes, over their first keys (here the date), then over the second key (here the value). Sum up the numbers in a new hash.
I'd move the code to sum the values to its own sub for clarity, then pass it the references of the hashes you want to sum up.
use strict;
use warnings;
sub sum {
my %sums;
foreach my $hash (#_) {
foreach my $date (keys %{$hash}) {
foreach my $val (keys %{$$hash{$date}}) {
$sums{$date}{$val} += $$hash{$date}{$val};
}
}
}
return %sums;
}
my %HASH1 = (
'2016-07-01' => {'val1' => '7', 'val2' => '9'},
'2016-07-02' => {'val1' => '10', 'val2' => '6'}
);
my %HASH2 = (
'2016-07-01' => {'val1' => '8', 'val2' => '4'},
'2016-07-03' => {'val1' => '3', 'val2' => '2'}
);
my %HASH3 = (
'2016-07-01' => {'val1' => '6', 'val2' => '5'},
'2016-07-02' => {'val1' => '1', 'val2' => '6'},
'2016-07-04' => {'val1' => '4', 'val2' => '2'}
);
my %sums = sum(\%HASH1, \%HASH2, \%HASH3);
foreach my $date (sort keys %sums) {
print "$date\n";
foreach my $val (keys %{$sums{$date}}) {
print " $val: $sums{$date}{$val}\n";
}
}

perl group results in hash using fetchrow_hashref

I want to group my results by countryid with the data shown below.
my #test = ();
my $st = qq[
SELECT id,countryID,abbrev
FROM myTable
];
my $q = $data->prepare($st);
$q->execute() or query_error($st);
while ( my $result = $q->fetchrow_hashref ) {
push #test, $result;
}
Using fetchrow_hashref I have no problem displayling the results
use Data::Dumper;
print STDERR Dumper(\#test);
returns
$VAR1 = [
{ 'id' => '1',
'countryID' => '1',
'title' => 'Title 1',
'abbrev' => 't1'
},
{ 'id' => '2',
'countryID' => '2',
'title' => 'Title 2',
'abbrev' => 't2'
},
{ 'id' => '3',
'countryID' => '3',
'title' => 'Title 3',
'abbrev' => 't3'
},
{ 'id' => '4',
'countryID' => '1',
'title' => 'Title 4',
'abbrev' => 't4'
}
];
I want to group it by countries as shown below.
$VAR1 = [
'countries' => {
'1' => [
{ 'id' => '1',
'title' => 'Title 1',
'abbrev' => 't1'
},
{ 'id' => '4',
'title' => 'Title 4',
'abbrev' => 't4'
}
],
'2' => [
{ 'id' => '2',
'title' => 'Title 2',
'abbrev' => 't2'
}
],
'3' => [
{ 'id' => '3',
'title' => 'Title 3',
'abbrev' => 't3'
}
]
}
];
How can I get this working in the while loop?
Ignoring the errors in your sample data structure, you are basically looking to convert form array of hashes to hash of hash of array of hashes. Once you have your initial data structure setup, you can do the following to create your new nested data structure:
for my $href ( #test ) {
my $id = $href->{countryID};
delete $href->{countryID};
push #{ $test2->{countries}{$id} }, $href;
}
Iterate each element of your array #test which basically is an array of hash references. Create a variable $id which will capture the countryID value from the hash. We delete it from the hash reference and then assign that hash reference to our new nested data structure which has countries as the first level key and the $id as the second level key.
We use push syntax to create our array of such references.
Note: As stated by thb in the comments, this does destroys your original data structure. If you'd like to retain the original structure, modify the code to the following:
for my $href ( #test ) {
my $copy = { %$href };
my $id = $copy->{countryID};
delete $copy->{countryID};
push #{ $test2->{countries}{$id} }, $copy;
}
You'll need to fix your syntax above a little (for example => instead of = >), but once you have done that, something like this should work nicely.
for (#$VAR1_orig) {
my %a = %$_;
my $countryID = $a{countryID};
delete $a{countryID};
push #{$VAR1->{countries}{$countryID}}, \%a;
}
(I have tried it on my computer, incidentally. It works.)
The above assumes that %$VAR1 is initially empty, then populates it according to #$VAR1_orig, after which you can do with $VAR1 whatever you like. (I assume that you know what %$ and #$ mean in Perl, but this is not a beginner's topic, as you may know. See man 1 perlref.)
Something like this, the input/output data structures might not be exactly what you have or want, you can patch that up.
use strict;
use Data::Dumper;
$a = [
{ 'id' => '1',
'countryID' => '1',
'title' => 'Title 1',
'abbrev' => 't1'
},
{ 'id' => '2',
'countryID' => '2',
'title' => 'Title 2',
'abbrev' => 't2'
},
{ 'id' => '3',
'countryID' => '3',
'title' => 'Title 3',
'abbrev' => 't3'
},
{ 'id' => '4',
'countryID' => '1',
'title' => 'Title 4',
'abbrev' => 't4'
}
];
my $b = {};
for my $item (#$a) {
if ( exists( $b->{ $item->{'countryID'} } ) ) {
push( #{ $b->{ $item->{'countryID'} } }, $item );
} else {
$b->{ $item->{'countryID'} } = [$item];
}
}
print Dumper($b);
The above prints:
$VAR1 = {
'1' => [
{ 'abbrev' => 't1',
'title' => 'Title 1',
'id' => '1',
'countryID' => '1'
},
{ 'abbrev' => 't4',
'title' => 'Title 4',
'id' => '4',
'countryID' => '1'
}
],
'3' => [
{ 'abbrev' => 't3',
'title' => 'Title 3',
'id' => '3',
'countryID' => '3'
}
],
'2' => [
{ 'abbrev' => 't2',
'title' => 'Title 2',
'id' => '2',
'countryID' => '2'
}
]
};

creating hash from variables to be used in json encode/decode perl

i'm trying to create a test module to test json encoding. i am having issues creating variables that will output correctly with the json encode/decode. if i use just the $cat_1 in the #cats array, it will work fine. however, using both, it prints out "HASH(..." as you can see below.
use strict;
use JSON;
use Data::Dump qw( dump );
my $cat_1 = {'name' => 'cat1', 'age' => '6', 'weight' => '10 kilos', 'type' => 'siamese'};
my $cat_2 = {'name' => 'cat2', 'age' => '10', 'weight' => '13 kilos', 'type' => 'siamese'};
my #cats;
push(#cats, $cat_1);
push(#cats, $cat_2);
my $dog_1 = {'name' => 'dog1', 'age' => '7', 'weight' => '20 kilos', 'type' => 'siamese'};
my $dog_2 = {'name' => 'dog2', 'age' => '5', 'weight' => '15 kilos', 'type' => 'siamese'};
my #dogs;
push(#dogs, $dog_1);
push(#dogs, $dog_2);
my $pets = {'cats' => #cats, 'dogs' => #dogs};
my $a = { 'id' => '123', 'name' => 'Joe Smith', 'city' => "Chicago", 'pets' => $pets };
my $json = JSON->new->allow_nonref;
my $encoded = $json->encode($a);
my $decoded = $json->decode( $encoded );
print "\ndump cat_1\n";
dump $cat_1;
print "\ndump cats\n";
dump #cats;
print "\n\nOriginal\n";
dump $a;
print "\n\n";
print "Encoded\n";
print $encoded;
print "\n\n";
print "Decoded\n";
dump $decoded;
print "\n\n";
output
dump cat_1
{ age => 10, name => "cat1", type => "siamese", weight => "10 kilos" }
dump cats
(
{ age => 10, name => "cat1", type => "siamese", weight => "10 kilos" },
{ age => 10, name => "cat2", type => "siamese", weight => "3 kilos" },
)
Original
{
city => "Chicago",
id => 123,
name => "Joe Smith",
pets => {
"cats" => { age => 10, name => "cat1", type => "siamese", weight => "10 kilos" },
"HASH(0x176c3170)" => "dogs",
"HASH(0x1785f2d0)" => { age => 10, name => "dog2", type => "siamese", weight => "3 kilos" },
},
}
Encoded
{"city":"Chicago","pets":{"HASH(0x1785f2d0)":{"weight":"3 kilos","name":"dog2","type":"siamese","age":"10"},"cats":{"weight":"10 kilos","name":"cat1","type":"siamese","age":"10"},"HASH(0x176c3170)":"dogs"},"name":"Joe Smith","id":"123"}
Decoded
{
city => "Chicago",
id => 123,
name => "Joe Smith",
pets => {
"cats" => { age => 10, name => "cat1", type => "siamese", weight => "10 kilos" },
"HASH(0x176c3170)" => "dogs",
"HASH(0x1785f2d0)" => { age => 10, name => "dog2", type => "siamese", weight => "3 kilos" },
},
}
This line
my $pets = {'cats' => #cats, 'dogs' => #dogs};
is a red flag. It's valid Perl, but it's not doing what you would expect. Perl will flatten your lists in this construction, so if #cats contains ($cat_1,$cat_2) and #dogs containts ($dog_1,$dog_2), your expression is parsed as
my $pets = { 'cats', $cat_1, $cat_2, 'dogs', $dog_1, $dog_2 };
which is like
my $pets = { 'cats' => $cat_1, $cat_2 => 'dogs', $dog_1 => $dog_2 }
with the hash references $cat_2 and $dog_1 getting stringified before being used as hash keys.
Hash values must be scalar values, not arrays. But array references are OK. Try:
my $pets = {'cats' => \#cats, 'dogs' => \#dogs};
The problem is in the creation of $pets:
my $pets = {'cats' => #cats, 'dogs' => #dogs};
Is roughly equivalent to:
my $pets = {'cats', {name => 'cat1', ...}, {name => 'cat2', ...},
'dogs', {name => 'dog1', ...}, {name => 'dog2, ...} };
Which is the same as:
my $pets = {
'cats' => {name => 'cat1', ...},
{name => 'cat2'}, => 'dogs',
{name => 'dog1', ...}, => {name => 'dog2}
};
You want to use ArrayRefs:
my $pets = {'cats' => \#cats, 'dogs' => \#dogs};
Which is:
my $pets = {
'cats' => [
{name => 'cat1', ...},
{name => 'cat2', ...},
],
'dogs' => [
{name => 'dog1', ...},
{name => 'dog2', ...},
],
};
Which is also how you could declare the whole data structure at once.

Resources