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.
Related
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'
]
];
I have a deep associated find and one association is retrieving too many none related records for modules_employees.
I should see only one record for modules_employees under the course_modules but it retrieves many because they can be many with course_modules_id but only one with courses_employee_id.
The modules_employees table
'id' => (int) 18,
'courses_employee_id' => (int) 31,
'course_module_id' => (int) 7,
'completed_on' => null,
CoursesEmployee->course->course_modules->modules_employees
CoursesEmployeesController.php
public function player($id = null)
{
$coursesEmployee = $this->CoursesEmployees->get($id, [
'contain' =>
[
'Employees',
'Courses',
'CourseModules',
'Courses.CourseModules',
'Courses.CourseModules.ModulesEmployees',
'Courses.CourseFiles'
]
]);
$this->set('coursesEmployee', $coursesEmployee);
debug($coursesEmployee);
$this->set('_serialize', ['coursesEmployee']);
}
The current find object, you will see one of the course_modules has two modules_employees when I should have one.
object(App\Model\Entity\CoursesEmployee) {
'id' => (int) 31,
'employee_id' => (int) 3,
'course_id' => (int) 3,
'course_module_id' => (int) 7,
'course_module' => object(App\Model\Entity\CourseModule) {
'id' => (int) 7,
'course_id' => (int) 3,
'name' => 'Module 2',
},
'course' => object(App\Model\Entity\Course) {
'id' => (int) 3,
'name' => 'Treacys Hotel Induction Training',
'course_files' => [
(int) 0 => object(App\Model\Entity\CourseFile) {
'id' => (int) 2,
'name' => 'Manual_Handling_doc.txt',
'type' => 'doc',
}
],
'course_modules' => [
(int) 0 => object(App\Model\Entity\CourseModule) {
'id' => (int) 6,
'course_id' => (int) 3,
'name' => 'Module 1',
'module_order' => (int) 1,
'modules_employees' => [
(int) 0 => object(App\Model\Entity\ModulesEmployee) {
'id' => (int) 1,
'courses_employee_id' => (int) 0,
'course_module_id' => (int) 6,
'started_on' => object(Cake\I18n\Time) {
'time' => '2015-09-08T04:16:16+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'completed_on' => object(Cake\I18n\Time) {
'time' => '2015-09-09T08:22:16+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'completed' => true,
'deleted' => null,
'[new]' => false,
'[accessible]' => [
'employee_id' => true,
'module_id' => true,
'started_on' => true,
'completed_on' => true,
'completed' => true,
'employee' => true,
'module' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[repository]' => 'ModulesEmployees'
}
],
'[repository]' => 'CourseModules'
},
(int) 1 => object(App\Model\Entity\CourseModule) {
'id' => (int) 7,
'course_id' => (int) 3,
'name' => 'Module 2',
'module_order' => (int) 2,
'modules_employees' => [
(int) 0 => object(App\Model\Entity\ModulesEmployee) {
'id' => (int) 2,
'courses_employee_id' => (int) 31,
'course_module_id' => (int) 7,
'started_on' => object(Cake\I18n\Time) {
'time' => '2015-09-17T00:00:00+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'completed_on' => null,
'[repository]' => 'ModulesEmployees'
},
(int) 1 => object(App\Model\Entity\ModulesEmployee) {
'id' => (int) 18,
'courses_employee_id' => (int) 32,
'course_module_id' => (int) 7,
'started_on' => object(Cake\I18n\Time) {
'time' => '2015-09-17T00:00:00+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'completed_on' => null,
'[repository]' => 'ModulesEmployees'
}
],
'[repository]' => 'CourseModules'
},
],
},
'employee' => object(App\Model\Entity\Employee) {
'id' => (int) 3,
'user_id' => (int) 4,
},
'[repository]' => 'CoursesEmployees'
}
You should look into matching
http://book.cakephp.org/3.0/en/orm/query-builder.html#filtering-by-associated-data
$query = $this->CoursesEmployees->findById($id)
->contain(['Your_Models_You_Wanna_Contain'])
->matching('Courses.CourseModules.ModulesEmployees', function ($q) use ($id) {
return $q->where(['courses_employee_id' => $id]);
});
if nothing matches then you wont get a CourseEmployee back aswell, if you would still need that you could also use contain:
http://book.cakephp.org/3.0/en/orm/retrieving-data-and-resultsets.html#passing-conditions-to-contain
$query = $this->CoursesEmployees->findById($id)->contain([
'Courses.CourseModules.ModulesEmployees' => function ($q) use ($id) {
return $q
->where(['courses_employee_id' => $id]);
}
]);
I've an array
$resultData = [
array("id"=>1,"name"=>"Cyrus","email"=>"risus#consequatdolorvitae.org"),
array("id"=>2,"name"=>"Justin","email"=>"ac.facilisis.facilisis#at.ca"),
array("id"=>3,"name"=>"Mason","email"=>"in.cursus.et#arcuacorci.ca"),
array("id"=>4,"name"=>"Fulton","email"=>"a#faucibusorciluctus.edu"),
array("id"=>5,"name"=>"Neville","email"=>"eleifend#consequatlectus.com"),
array("id"=>6,"name"=>"Jasper","email"=>"lectus.justo#miAliquam.com"),
array("id"=>7,"name"=>"Neville","email"=>"Morbi.non.sapien#dapibusquam.org"),
array("id"=>8,"name"=>"Neville","email"=>"condimentum.eget#egestas.edu"),
array("id"=>9,"name"=>"Ronan","email"=>"orci.adipiscing#interdumligulaeu.com"),
array("id"=>10,"name"=>"Raphael","email"=>"nec.tempus#commodohendrerit.co.uk"),
];
A dataprovider :
$dataProvider = new ArrayDataProvider([
'key'=>'id',
'allModels' => $resultData,
'sort' => [
'attributes' => ['id', 'name', 'email'],
],
]);
And the Gridview :
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'id',
[
'attribute' => 'name',
'value' => 'name',
],
[
"attribute" => "email",
'value' => 'email',
]
]
]);
As is, the code make me View the array in a grid, and the possibility to sort it when clicking on columns. That's ok.
But how to do to use filtering ?
I tried with the following :
$searchModel = ['id' => null, 'name' => '', 'email' => ''];
echo GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'id',
[
'attribute' => 'name',
'value' => 'name',
],
[
"attribute" => "email",
'filter' => '<input class="form-control" name="filteremail" value="da" type="text">',
'value' => 'email',
]
]
]);
But it's not working.
Does I have to filter myself the object depending on the $get value ?
My solution with full code :
$resultData = [
array("id"=>1,"name"=>"Cyrus","email"=>"risus#consequatdolorvitae.org"),
array("id"=>2,"name"=>"Justin","email"=>"ac.facilisis.facilisis#at.ca"),
array("id"=>3,"name"=>"Mason","email"=>"in.cursus.et#arcuacorci.ca"),
array("id"=>4,"name"=>"Fulton","email"=>"a#faucibusorciluctus.edu"),
array("id"=>5,"name"=>"Neville","email"=>"eleifend#consequatlectus.com"),
array("id"=>6,"name"=>"Jasper","email"=>"lectus.justo#miAliquam.com"),
array("id"=>7,"name"=>"Neville","email"=>"Morbi.non.sapien#dapibusquam.org"),
array("id"=>8,"name"=>"Neville","email"=>"condimentum.eget#egestas.edu"),
array("id"=>9,"name"=>"Ronan","email"=>"orci.adipiscing#interdumligulaeu.com"),
array("id"=>10,"name"=>"Raphael","email"=>"nec.tempus#commodohendrerit.co.uk"),
];
function filter($item) {
$mailfilter = Yii::$app->request->getQueryParam('filteremail', '');
if (strlen($mailfilter) > 0) {
if (strpos($item['email'], $mailfilter) != false) {
return true;
} else {
return false;
}
} else {
return true;
}
}
$filteredresultData = array_filter($resultData, 'filter');
$mailfilter = Yii::$app->request->getQueryParam('filteremail', '');
$namefilter = Yii::$app->request->getQueryParam('filtername', '');
$searchModel = ['id' => null, 'name' => $namefilter, 'email' => $mailfilter];
$dataProvider = new \yii\data\ArrayDataProvider([
'key'=>'id',
'allModels' => $filteredresultData,
'sort' => [
'attributes' => ['id', 'name', 'email'],
],
]);
echo GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'id',
[
'attribute' => 'name',
'value' => 'name',
],
[
"attribute" => "email",
'filter' => '<input class="form-control" name="filteremail" value="'. $searchModel['email'] .'" type="text">',
'value' => 'email',
]
]
]);
On the previous soultion. I created a loop to make the filters, columns and searchModel.
$items = [
array("id" => 1, "name" => "Cyrus", "email" => "risus#consequatdolorvitae.org"),
array("id" => 2, "name" => "Justin", "email" => "ac.facilisis.facilisis#at.ca"),
array("id" => 3, "name" => "Mason", "email" => "in.cursus.et#arcuacorci.ca"),
array("id" => 4, "name" => "Fulton", "email" => "a#faucibusorciluctus.edu"),
array("id" => 5, "name" => "Neville", "email" => "eleifend#consequatlectus.com"),
array("id" => 6, "name" => "Jasper", "email" => "lectus.justo#miAliquam.com"),
array("id" => 7, "name" => "Neville", "email" => "Morbi.non.sapien#dapibusquam.org"),
array("id" => 8, "name" => "Neville", "email" => "condimentum.eget#egestas.edu"),
array("id" => 9, "name" => "Ronan", "email" => "orci.adipiscing#interdumligulaeu.com"),
array("id" => 10, "name" => "Raphael", "email" => "nec.tempus#commodohendrerit.co.uk"),
];
$searchAttributes = ['id', 'name', 'email'];
$searchModel = [];
$searchColumns = [];
foreach ($searchAttributes as $searchAttribute) {
$filterName = 'filter' . $searchAttribute;
$filterValue = Yii::$app->request->getQueryParam($filterName, '');
$searchModel[$searchAttribute] = $filterValue;
$searchColumns[] = [
'attribute' => $searchAttribute,
'filter' => '<input class="form-control" name="' . $filterName . '" value="' . $filterValue . '" type="text">',
'value' => $searchAttribute,
];
$items = array_filter($items, function($item) use (&$filterValue, &$searchAttribute) {
return strlen($filterValue) > 0 ? stripos('/^' . strtolower($item[$searchAttribute]) . '/', strtolower($filterValue)) : true;
});
}
echo GridView::widget([
'dataProvider' => new ArrayDataProvider([
'allModels' => $items,
'sort' => [
'attributes' => $searchAttributes,
],
]),
'filterModel' => $searchModel,
'columns' => array_merge(
$searchColumns, [
['class' => 'yii\grid\ActionColumn']
]
)
]);
here are some improvements for the filtering function
function ($item) {
$mailfilter = strtolower(Yii::$app->request->getQueryParam('filteremail', ''));
if (strlen($mailfilter) > 0) {
return strpos(strtolower($item['email']), $mailfilter) !== false;
} else {
return true;
}
}
Use strtolower() in both places($item['email']) & mailfilter) function if you want your filter to be not case sensitive
Check also type for strpos() ("!== false" instead of "!= false") function, otherwise, it will not work while trying to filter for the first characters of the string
A dataprovider :
if ($this->load($params)) {
$name = strtolower(trim($this->name));
$resultData= array_filter($resultData, function ($role) use ($name){
return (empty($name) || strpos((strtolower(is_object($role) ? $role->name : $role['name'])),$name) !== false);
});
}
$dataProvider = new ArrayDataProvider([
'key'=>'id',
'allModels' => $resultData,
'sort' => [
'attributes' => ['id', 'name', 'email'],
],
]);
https://getyii.com/topic/736
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));
I have two array of hashes .Both have similar values in them but i want to create new key in the hash that will have the some values of second array of hash.
First Array:
[
{ area_code => 93, name => 'Afghanistan', code => 'AF', slno => 4554 },
{ area_code => 1684, name => 'American Samoa', code => 'AS', slno => 4557 },
];
Second Array:
[
{ city => "Berat", country => "AS", id => 134368 },
{ city => "Durres", country => "AS", id => 138466 },
{ city => "Kabul", country => "AF", id => 142462 },
];
Now in the first hash i have key code whose value is similar to the second hash key country .So i want to add a new key in the second array of hash which will be country_name.And the country_name value will be the value of first array of hash name.
So how can we do this please help me in this
use strict;
use warnings;
my $a1 = [
{ area_code => 93, code => "AF", name => "Afghanistan", slno => 4554 },
{ area_code => 1684, code => "AS", name => "American Samoa", slno => 4557 },
];
my $a2 = [
{ city => "Berat", country => "AS", id => 134368 },
{ city => "Durres", country => "AS", id => 138466 },
{ city => "Kabul", country => "AF", id => 142462 },
];
my %h = map { $_->{code} => $_ } #$a1;
for my $v (#$a2) {
$v->{country_name} = $h{ $v->{country} }{name};
}
This is a similar idea to #mpapec's, but, I think, a little cleaner.
use strict;
use warnings;
my #array1 = (
{ area_code => 93, name => 'Afghanistan', code => 'AF', slno => 4554 },
{ area_code => 1684, name => 'American Samoa', code => 'AS', slno => 4557 },
);
my #array2 = (
{ country => 'AS', city => 'Berat', id => 134368 },
{ country => 'AS', city => 'Durres', id => 138466 },
{ country => 'AF', city => 'Kabul', id => 142462 },
);
{
my %names = map { $_->{code} => $_->{name} } #array1;
$_->{country_name} = $names{ $_->{country} } for #array2;
}
use Data::Dump;
dd \#array2;
output
[
{
country => 'AS',
city => 'Berat',
id => 134368,
country_name => 'American Samoa',
},
{
country => 'AS',
city => 'Durres',
id => 138466,
country_name => 'American Samoa',
},
{
country => 'AF',
city => 'Kabul',
id => 142462,
country_name => 'Afghanistan',
},
]