how to build nested array from other nested array php - php

I have array where each element is array of sql columns.
One element of MAIN array looks like this:
Array(
[type] => water
[id] => KK
[animalName] => "josip"
[key] => 123
[key2] => 2
[alive] => true
[name] => "Lilly"
[key] => 1
[big] => false
)
now i need to build nested array which looks like this:
array(
[type] => water
[id] => KK
["animals"] => array(
[animalName] => "josip"
[key] => 123
[key2] => 1.5
[alive] => true
["babies" => array(
[name] => "jimmy"
[key] => 1
[big] => false
)
)
as long as type == type in previous element of MAIN array i need to add more animals, so
array(
[type] => water
[id] => KK
["animals"] => array(
[animalName] => "rom"
[key] => 213
[key2] => 5423
[alive] => true
["babies" => array(
[name] => "julia"
[key] => 199
[big] => false
)
)
["animals"] => array(
[key] => 123123111
[key2] => 123213
[alive] => true
[name] => "tom"
["babies" => array(
[name] => "robert"
[key] => 1123
[big] => false
)
)
i have built an algorithm but it was really complex and unoptimal so im looking for as simple as possible solution, any ideas?
the point is to get json with structure:
{
"type":"water",
"id":"KK",
"animals":[
{
"AnimalName":"crocodile",
"key":1,
"key2":1.1,
"alive":true,
"babies":[
{
"name":"jimmy",
"Key":123,
"big":false
}
]
},
{
"AnimalName":"fish",
"key":22,
"key2":1.5,
"alive":true,
"babies":[
{
"name":"lilly",
"key2":5,
"big":false
}
]
}
],
"type":"land",
"id":"LL",
"animals":[
{
"AnimalName":"lion",
"key":1,
"key2":1.1,
"alive":true,
"babies":[
{
"name":"jimmy",
"Key":123,
"big":false
}
]
},
{
"AnimalName":"dog",
"key":22,
"key2":1.5,
"alive":true,
"babies":[
{
"name":"lilly",
"key2":5,
"big":false
}
]
}
]
}
as long as type == type in previous element of main array add more animals, if type differs from previus add next element to root array with other type and add other animals.
Im sorry if its messy a little

try this, it will helpful for you..
$array = array(
'type' => 'water',
'id' => 'KK',
'animalName' => "josip",
'key' => 123,
'key2' => 2,
'alive' => 'true',
'name' => "Lilly",
'key3' => 1,
'big' => 'false'
);
$resulArray = array();
foreach ($array as $key => $value) {
if ($key == 'animalName' || $key == 'key' || $key == 'key2' || $key == 'alive') {
$resulArray['animals'][$key] = $value;
}
else if ($key == 'name' || $key == 'key3' || $key == 'big') {
$resulArray['animals']['babies'][$key] = $value;
} else {
$resulArray[$key] = $value;
}
}
// return array
echo '<pre>';
print_r($resulArray);
// return json
$resulJson = json_encode($resulArray);
echo '<pre>';
print_r($resulJson);

Related

How do I get values from this array? PHP

Very much new to PHP and completely stuck because of #attributes when trying to pick values out of an array. I have previously converted an xml file into a associative array.
print_r(array_keys($newArray));
Prints:
Array ( [0] => #attributes [1] => rate )
print_r ($newArray);
Prints:
Array (
[#attributes] => Array (
[base] => GBP
[ts] => 1572881347 )
[rate] => Array (
[0] => Array (
[#attributes] => Array (
[code] => AED
[rate] => 4.739532203531
[live] => 0
)
)
[1] => Array (
[#attributes] => Array (
[code] => AFN
[rate] => 100.80144337913
[live] => 0
)
)
[2] => Array (
[#attributes] => Array (
[code] => ALL
[rate] => 142.29721877018
[live] => 0
)
)
[3] => Array (
[#attributes] => Array (
[code] => AMD
[rate] => 614.98298701028
[live] => 0
)
)
How would I specify and print the last value?
[3] => Array ( [#attributes] => Array ( [code] => AMD [rate] => 614.98298701028 [live] => 0.
With the goal to output something like: AMD, 614.98298701028, 0
Thanks
More generally, if you'd want to look-up a currency in your array, you could use following recursive function:
$code = 'AMD'; // set the curncy you want to lookup
forex($code, $newArray); // invoke the recursive function
// output:
//code : AMD
//rate : 614.98298701028
function forex(string $code = '', array $arr = []): void
{
foreach ($arr as $key => $value) {
if (is_array($value) && $key !== '#attributes') {
forex($code, $value);
} else {
if (isset($value['code']) && $value['code'] == $code) {
echo 'code : ' . $value['code'];
echo '<br />';
echo 'rate : ' . $value['rate'];
echo '<br />';
}
}
}
}
working demo
Assuming that your original array is something like this:
$a = array(
'#attributes' => array(
'base' => 'GBP',
'ts' => 1572881347),
'rate' => array(
0 => array(
'#attributes' => array(
'code' => 'AED',
'rate' => 4.739532203531,
'live' => 0,
),
),
1 => array(
'#attributes' => array(
'code' => 'AFN',
'rate' => 100.80144337913,
'live' => 0,
),
),
2 => array(
'#attributes' => array(
'code' => 'ALL',
'rate' => 142.29721877018,
'live' => 0,
),
),
3 => array(
'#attributes' => array(
'code' => 'AMD',
'rate' => 614.98298701028,
'live' => 0,
),
)));
then you can get what you want with this:
$last_rate = sizeof($a['rate']) - 1;
foreach ($a['rate'][$last_rate]['#attributes'] as $key => $value) {
echo "$value ";
}
Which will output:
AMD 614.98298701028 0
If your array will always contain the array values under rate, you can retrieve the last element of the rate array by using end($newArray['rate']).
To output a CSV style string you can simply use implode(', ', $last['#attributes']) or another desired method, such as foreach, to display the values from the last element.
Example: https://3v4l.org/FNuuZ
if ($last = end($newArray['rate'])) {
echo implode(', ', $last['#attributes']);
}
Result:
AMD, 614.98298701028, 0

Merging multidimensional arrays by matching key-value pairs of subarrays?

The task is to merge ("inexpensively") two arrays, which have matching key-value pairs of subarrays. E.g.:
Array 1:
Array
(
[0] => Array
(
[count] => 1
[da_table] => article
[da_class] => classes\elements\tables\Article
[da_page_class] => Page_Article
)
[1] => Array
(
[count] => 2
[da_table] => client_contract_specification_price
[da_class] => classes\elements\tables\ClientContractSpecificationPrice
[da_page_class] => Page_ClientContractSpecification
)
[2] => Array
(
[count] => 2
[da_table] => supplier
[da_class] => classes\elements\tables\Supplier
[da_page_class] => Page_Supplier
)
)
Array 2:
Array
(
[0] => Array
(
[name] => Articles
[name_short] =>
[da_page_class] => Page_Article
)
[1] => Array
(
[name] => Client contract specifications
[name_short] => cc_specifications
[da_page_class] => Page_ClientContractSpecification
)
[2] => Array
(
[name] => Suppliers
[name_short] =>
[da_page_class] => Page_Supplier
)
)
How to merge the two above arrays by a matching [da_page_class] => ... pairs, so the resulting array will contain both key-values of the first and the second array, i.e.:
...
[0] => Array
(
[count] => 1
[da_table] => article
[da_class] => classes\elements\tables\Article
[da_page_class] => Page_Article
[name] => Articles
[name_short] =>
)
...
Additional requirements:
Subarrays may come in random order. Also, there can be "orphans", which contain values of ['da_page_class'], but have no match in another array. These should be ignored.
Well, you simply iterate over the array elements and combine them:
<?php
$data1 = [
[
'count' => 1,
'da_table' => 'article',
'da_class' => 'classes\elements\tables\Article',
'da_page_class' => 'Page_Article'
],
[
'count' => 2,
'da_table' => 'client_contract_specification_price',
'da_class' => 'classes\elements\tables\ClientContractSpecificationPrice',
'da_page_class' => 'Page_ClientContractSpecification'
],
[
'count' => 2,
'da_table' => 'supplier',
'da_class' => 'classes\elements\tables\Supplier',
'da_page_class' => 'Page_Supplier'
]
];
$data2 = [
[
'name' => 'Articles',
'name_short' => null,
'da_page_class' => 'Page_Article'
],
[
'name' => 'Client contract specifications',
'name_short' => 'cc_specifications',
'da_page_class' => 'Page_ClientContractSpecification'
],
[
'name' => 'Suppliers',
'name_short' => null,
'da_page_class' => 'Page_Supplier'
]
];
$output = [];
for ($i=0; $i<count($data1); $i++) {
$output[$i] = array_merge($data1[$i], $data2[$i]);
}
print_r($output);
The output obviously is:
Array
(
[0] => Array
(
[count] => 1
[da_table] => article
[da_class] => classes\elements\tables\Article
[da_page_class] => Page_Article
[name] => Articles
[name_short] =>
)
[1] => Array
(
[count] => 2
[da_table] => client_contract_specification_price
[da_class] => classes\elements\tables\ClientContractSpecificationPrice
[da_page_class] => Page_ClientContractSpecification
[name] => Client contract specifications
[name_short] => cc_specifications
)
[2] => Array
(
[count] => 2
[da_table] => supplier
[da_class] => classes\elements\tables\Supplier
[da_page_class] => Page_Supplier
[name] => Suppliers
[name_short] =>
)
)
Alternatively you could also merge the contents of the elements of the second array into the corresponding elements of the first array. That reduces the memory footprint for large data sets.
Considering the additional requirement you specified in your comment I changed the merge strategy to allow for arbitrary orders of the two sets:
<?php
$data1 = [
[
'count' => 1,
'da_table' => 'article',
'da_class' => 'classes\elements\tables\Article',
'da_page_class' => 'Page_Article'
],
[
'count' => 2,
'da_table' => 'client_contract_specification_price',
'da_class' => 'classes\elements\tables\ClientContractSpecificationPrice',
'da_page_class' => 'Page_ClientContractSpecification'
],
[
'count' => 2,
'da_table' => 'supplier',
'da_class' => 'classes\elements\tables\Supplier',
'da_page_class' => 'Page_Supplier'
]
];
$data2 = [
[
'name' => 'Articles',
'name_short' => null,
'da_page_class' => 'Page_Article'
],
[
'name' => 'Client contract specifications',
'name_short' => 'cc_specifications',
'da_page_class' => 'Page_ClientContractSpecification'
],
[
'name' => 'Suppliers',
'name_short' => null,
'da_page_class' => 'Page_Supplier'
]
];
$output = [];
array_walk($data1, function($entry, $key) use (&$output, $data2) {
$output[$key] = $entry;
foreach($data2 as $cand) {
if ($entry['da_page_class'] == $cand['da_page_class']) {
$output[$key] = array_merge($output[$key], $cand);
}
}
});
print_r($output);
The resulting output obviously is identical to above.
O(m*n) solution:
$result = array();
foreach ($array1 as $value1) {
// do not handle elements without pageclass
if (!array_key_exists('da_page_class', $value1) || !$value1['da_page_class']) {
continue;
}
foreach ($array2 as $value2) {
if (!array_key_exists('da_page_class', $value2) || !$value2['da_page_class']) {
continue;
}
if ($value1['da_page_class'] == $value2['da_page_class']) {
array_push($result, $value1 + $value2)
break;
}
}
}
print_r($result);
O(m+n) solution:
$result = array();
foreach ($array1 as $value) {
// do not handle elements without pageclass
if (!array_key_exists('da_page_class', $value) || !$value['da_page_class']) {
continue;
}
$result[$value['da_page_class']] = $value;
}
foreach ($array2 as $value) {
if (
// do not handle elements without pageclass
!array_key_exists('da_page_class', $value) || !$value['da_page_class'] ||
// do not handle elements that do not exist in array 1
!array_key_exists($value['da_page_class'], $result)
) {
continue;
}
// merge values of this pageclass
$result[$value['da_page_class']] = array_merge($result[$value['da_page_class']], $value);
}
print_r($result);
EDIT: added O(m+n) solution

Deep Associative Array to adjacent mysql table

Been fighting the whole night. Giving up. I have an adjacent table in mysql:
id, parentid,name,design,path,sort
The depth is maximum four and using mysql query, I print out the results to UL list successfully. From there, items are added, sorted and edited as well as removed. Then when button is clicked, I send the result back to php. The data been sent is JSON and it does get recieved.
json_decode() gives the following sample:
Array ( [0] => Array ( [cls] => [path] => # [id] => 1 [name] =>BLOCKA ) [1] => Array ( [cls] => [path] => # [id] => 2 [name] => BLOCKB [children] => Array ( [0] => Array ( [cls] => [path] => # [id] => 3 [name] => CLASSB1 [children] => Array ( [0] => Array ( [cls] => [path] => # [id] => 7 [name] => CLASSB12 ) ) ) [1] => Array ( [cls] => [path] => # [id] => 4 [name] => CLASSSB13 [children] => Array ( [0] => Array ( [cls] => [path] => # [id] => 5 [name] => CLASSB4 ) [1] => Array ( [cls] => [path] => # [id] => 6 [name] => CLASSB5 ) ) ) ) ) )
Graphically:
BLOCKA
BLOCKB
CLASSB1
CLASSB3
...
I am using jquery.nested
Now my problem is looping through the array, getting id of the parent then add child.
The closest I came with is
function dissect($blocks) {
if (!is_array($blocks)) {
echo $blocks;
return;
}
foreach($blocks as $block) {
dissect($block);
}
}
It does process each element but not in the way I want. Sorry for my broken english...any help would be appreciated.
First iterate through blocks getting the parent, if children exists in parent block, loop through the children.
There might be other better way to implement this, you can try below code:
$blocks = array (
"0" => array (
"cls" => "",
"path" => array(
"id" => 1,
"name" =>"BLOCKA",
)
),
"1" => array (
"cls" => "",
"path" => array(
"id" => 2,
"name" => "BLOCKB" ,
"children" => array (
"0" => array (
"cls" => "",
"path" => array(
"id" => 3,
"name" => "CLASSB1" ,
"children" => array (
"0" => array (
"cls" => "",
"path" => array(
"id" => 7,
"name" => "CLASSB12" ,
),
),
),
),
),
"1" => array (
"cls" => "",
"path" => array(
"id" => 4,
"name" => "CLASSSB13" ,
"children" => array (
"0" => array (
"cls" => "",
"path" => array(
"id" => 5,
"name" => "CLASSB4" ,
),
),
"1" => array (
"cls" => "",
"path" => array(
"id" => 6,
"name" => "CLASSB5",
),
),
),
),
),
),
),
),
) ;
echo "<pre>";
/*loop through blocks*/
foreach ($blocks as $key => $block) {
echo $block['path']['name'].'<br/>'; /* echo parent*/
if (isset($block['path']['children'])) {
loopChildren($block['path']['children']); /* children loop*/
}
}
/*Loop through childrens*/
function loopChildren($childrens, $prefix = '-')
{
foreach ($childrens as $key => $child) {
getChild($child, $prefix);
}
}
/*Get the child and loop sub-children if exist*/
function getChild($child, $prefix='-')
{
echo $prefix. $child['path']['name'].'<br/>'; /*echo child*/
if (isset($child['path']['children'])) {
$prefix .= '-';
loopChildren($child['path']['children'], $prefix); /* sub-children loop*/
}
}
echo "</pre>";
The output:
BLOCKA
BLOCKB
-CLASSB1
--CLASSB12
-CLASSSB13
--CLASSB4
--CLASSB5
thanks for your tip. It guided me to an answer that worked for me. I ended up using two functions. The error was "index out of bound"...here is what I did now...with calls to the mysql table:
$response = json_decode($_POST['s'], true); // decoding received JSON to array
if(is_array($response)){
//start saving now
$order=1;
foreach ($response as $key => $block) {
//0 is for blocks: no parent id needed
$parentid=$this->Blocks_model->insertblock($block['name'],$block['cls'],0,$block['path'],$order);
if (isset($block['children'])) {
$this->childblocks($parentid,$block['children']);
}
$order++;
}
}
private function childblocks($parentid,$e){
$order=1;
foreach ($e as $key => $block) {
$parentid=$this->Blocks_model->insertblock($block['name'],$block['cls'],0,$block['path'],$order);
if (isset($block['children'])) {
$this->childblocks($parentid,$block['children']);
}
$order++;
}
}

PHP multiple duplicate values in multidimensional array

I am trying to update the below array to set "duplicate" => true when both "name" and "date" are the same. In the below example 'array[1][duplicate]=>true' as both
array[0] & array[1] have the same "name"=john & "date"=2015-7-24
Array
(
[0] => Array
(
[id] => 1
[name] => john
[date] => 2015-07-24
[duplicate] => false
)
[1] => Array
(
[id] => 1
[name] => john
[date] => 2015-07-24
[duplicate] => false
)
[2] => Array
(
[id] => 1
[name] => jane
[date] => 2015-07-24
[duplicate] => false
)
[3] => Array
(
[id] => 1
[name] => notJaneORJohn
[date] => 2015-07-24
[duplicate] => false
)
[4] => Array
(
[id] => 1
[name] => jane
[date] => 2099-07-24
[duplicate] => false
)
)
Try this,
$array = Array
(
0 => Array
(
'id' => '1',
'name' => 'john',
'date' => '2015-07-24',
'duplicate' => 'false',
),
1 => Array
(
'id' => 1,
'name' => 'john',
'date' => '2015-07-24',
'duplicate' => 'false'
),
2 => Array
(
'id' => 1,
'name' => 'jane',
'date' => '2015-07-24',
'duplicate' => 'false'
),
3 => Array
(
'id' => 1,
'name' => 'notJaneORJohn',
'date' => '2015-07-24',
'duplicate' => 'false'
),
4 => Array
(
'id' => 1,
'name' => 'jane',
'date' => '2099-07-24',
'duplicate' => 'false'
)
);
foreach ($array as $key => $value) {
for ($i = $key + 1 ; $i < sizeof($array); $i++) {
if ($value['name'] === $array[$i]['name'] && $value['date'] === $array[$i]['date']) {
$array[$key]['duplicate'] = 'TRUE';
$array[$i]['duplicate'] = 'TRUE';
}
}
}
This would work:
$Arr = Array(
['id'=>1, 'name'=>'john', 'date'=>'2015-07-24', 'duplicate'=>0],
['id'=>1, 'name'=>'john', 'date'=>'2015-07-24', 'duplicate'=>0],
['id'=>1, 'name'=>'Jane', 'date'=>'2015-07-24', 'duplicate'=>0]
);
foreach($Arr as $i1 => $v1){
$Str1 = $v1['name'].$v1['date'];
foreach($Arr as $i2 => $v2){
if( $i1 !== $i2 && $Str1 === $v2['name'].$v2['date'] ){
$Arr[$i1]['duplicate'] = 1;
}
}
}
echo '<pre>',print_r($Arr),'</pre>'; die();
... outputs:
Array(
[0] => Array
(
[id] => 1
[name] => john
[date] => 2015-07-24
[duplicate] => 1
)
[1] => Array
(
[id] => 1
[name] => john
[date] => 2015-07-24
[duplicate] => 1
)
[2] => Array
(
[id] => 1
[name] => Jane
[date] => 2015-07-24
[duplicate] => 0
)
)
Have a look at this shortcut method ;)
<?php $testarr = array(
array("id" => 1,"name" => "john","date" => "2015-07-24","duplicate" => "false"),
array("id" => 1,"name" => "john","date" => "2015-07-24","duplicate" => "false"),
array("id" => 1,"name" => "jane","date" => "2015-07-24","duplicate" => "false"),
array("id" => 1,"name" => "notJaneORJohn","date" => "2015-07-24","duplicate" => "false"),
array("id" => 1,"name" => "jane","date" => "2099-07-24","duplicate" => "false")
);
$tempArray = array();
function checkDuplicate(&$arr) {
global $tempArray;
if (count($tempArray) > 0 && in_array($arr['name'], $tempArray) && in_array($arr['date'], $tempArray)) {
$arr['duplicate'] = "true";
} else {
$tempArray[] = $arr['name'];
$tempArray[] = $arr['date'];
}
}
array_walk($testarr, 'checkDuplicate');
print_r($testarr);

Make array unique in multidimensional array php codeigniter

I have this array
Array (
[0] => Array
(
[0] => stdClass Object
(
[id] => 226
[user_id] => 1
[name] => Eden Corner Tub by Glass - $2099
)
[1] => stdClass Object
(
[id] => 225
[user_id] => 1
[name] => Blue Quilted Leather Jacket by Minusey - $499
)
[2] => stdClass Object
(
[id] => 222
[user_id] => 1
[name] => Darling New Bathtub by Duravit - $6300
)
)
[1] => Array
(
[0] => stdClass Object
(
[id] => 226
[user_id] => 1
[name] => Eden Corner Tub by Glass - $2099
)
[1] => stdClass Object
(
[id] => 229
[user_id] => 1
[name] => Batman Tumbler Golf Cart - $50000
)
[2] => stdClass Object
(
[id] => 228
[user_id] => 1
[name] => Swirlio Frozen Fruit Dessert Maker - $60
)
) )
I have an array of products that I need to make sure are unique.
Need to make this array unique by id. These array are generated by pushing value.
I'm trying to solve this for more than a week now, but I dont get it to work. I know it should be easy...but anyway - I don't get it :D
Try this:
$array = array(
0 => array(
"name" => "test",
"id" => 4
),
1 => array(
"name" => "test2",
"id" => 152
),
2 => array(
"name" => "test2",
"id" => 152
)
);
$newArray = array();
foreach($array as $value) {
$newArray[$value['id']]['name'] = $value['name'];
$newArray[$value['id']]['id'] = $value['id'];
}
foreach($array as $key=>$inner_array)
{
foreach($array as $key_again=>$array_again)
{
if($key != $key_again)
{
if($inner_array['name'] != $array_again['name'] AND $inner_array['id'] != $array_again['id'])
{
//its okay
}
else
{
unset($array[$key]);
}
}
}
}
Not sure how the arrays are generated, but, if you can change that, you could set the array keys to the IDs directly and check if the id is already set.
Otherwise, you can do the following:
$unique = array();
foreach( $array as $values ) {
if( ! isset( $unique[$values['id']] ) ) {
$unique[$values['id']] = $values;
}
}
This will make your array unique:
$array = array(
0 => array(
"name" => "test",
"id" => 4
),
1 => array(
"name" => "test2",
"id" => 152
),
2 => array(
"name" => "test2",
"id" => 152
) );
$result = array();
$index = array();
foreach($array as $i => $elem) {
if(!isset($index[$elem['id']])) {
$result[$i] = $elem;
$index[$elem['id']] = 1;
}
}
echo var_export($result);
Output:
array (
0 =>
array (
'name' => 'test',
'id' => 4,
),
1 =>
array (
'name' => 'test2',
'id' => 152,
),
)
This will work. It could be considered more clean than a for loop, but I'm not sure about performance.
$array = [
[ "name" => "test", "id" => 4 ],
[ "name" => "test2", "id" => 152 ],
[ "name" => "test2", "id" => 152 ]
];
array_walk($array, function(&$item, $idx) use($array){
$matches = array_slice(array_keys($array, $item), 1);
if (in_array($idx, $matches)) {
$item = false;
}
});
$array = array_filter($array);
Edit Since you updated the data set to work with, you would need to flatten it 1 level:
$array = call_user_func_array('array_merge', $array);

Categories