perl group results in hash using fetchrow_hashref - arrays

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

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 dynamic multidimensional array [duplicate]

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

how i can fetch user data in a manyToMany association

I have a problem with CakePHP. I tested many ways, but can't find a solution for it.
I have these tables:
users
id
name
country_code
countries
code
title
skills
code
title
roles
id
title
events
id
title
country_code
events_users
event_id
user_id
role_id
skill_code
events hasAndBelongsToMany users and events_users is my join table, and when I read data, it gives me something like this:
array(
(int) 0 => array(
'Event' => array(
'id' => '1',
'title' => '40th WorldSkills Competitions',
'year' => '2011',
'country_code' => 'LV',
'created' => '2013-02-08 00:00:00'
),
'User' => array(
(int) 0 => array(
'password' => '*****',
'id' => '14',
'name' => 'test',
'family' => 'testian',
'username' => 'test#mail.me',
'country_code' => 'BR',
'telphone' => '465465',
'avatar' => 'avatar_51299c1da268f20110912043238_rodekamp_04.jpg',
'address' => 'AA',
'admin' => '0',
'created' => '2013-02-24 05:50:37',
'modified' => '2013-02-24 05:50:37',
'EventsUser' => array(
'id' => '1',
'user_id' => '14',
'event_id' => '1',
'role_id' => '1',
'skill_code' => '17',
'manage' => '100'
)
),
(int) 1 => array(
'password' => '*****',
'id' => '5',
'name' => 'John',
'family' => 'Smith',
'username' => 'john#me.com',
'country_code' => 'IE',
'telphone' => '147',
'avatar' => '20120504124040_franziska_peter_ok.jpg',
'address' => 'No 55',
'admin' => '0',
'created' => '2013-02-10 15:24:13',
'modified' => '2013-02-10 15:28:50',
'EventsUser' => array(
'id' => '2',
'user_id' => '5',
'event_id' => '1',
'role_id' => '2',
'skill_code' => '17',
'manage' => '0'
)
),
(int) 2 => array(
'password' => '*****',
'id' => '4',
'name' => 'hadi',
'family' => 'mm',
'username' => 'design.zerzem#gmail.com',
'country_code' => 'AE',
'telphone' => '415456',
'avatar' => '',
'address' => 'sadjfklsaf asd f',
'admin' => '0',
'created' => '2013-02-10 09:01:28',
'modified' => '2013-02-24 06:43:42',
'EventsUser' => array(
'id' => '3',
'user_id' => '4',
'event_id' => '1',
'role_id' => '4',
'skill_code' => '17',
'manage' => '0'
)
)
)
It's ok, but with events_users I want get data about skill and role that are in events_users (skill_code and role_id). How should I create models to give me all this data?
I think reading about "hasMany Through" should answer your question.
Basically, you make a model for your join table, then you can associate it like any other model.
When you go to retrieve your data, use CakePHP's Containable behavior (if you haven't used it before, be prepared to get addicted to it).

Resources