Im trying to create multi-dimesional array with unlimited depth.
I select the data from the database and check it if the field 'isArray' is true, meaning this column is a parent then I tried to make a loop to make it look for its child 'parent_id' => $row->id.
I'm expecting output like this.
array(
[0]=> array(
'id' => '29',
'section' => '',
'sorting' =>'',
'title' => 'POWERS OF THE BANKO SENTRAL',
'pdf_file' => '',
'content' => '',
'parent_id' => '0',
'isArray' => array(
[0] => array(
'id' => '30',
'section' => '001',
'sorting' => '',
'title' => 'Examination by the Bangko Sentral',
'pdf_file' => 'NRBSL CHRISTMAS PARTY RAFFLE WINNERS.pdf',
'parent_id' => '29',
'isArray' => 0,
),
[1] => array(
'id' => '31',
'section' => '002',
'sorting' => '',
'title' => 'Supervisory Enforcement',
'pdf_file' => 'APL-Form1.pdf'
'parent_id' => '29',
'isArray' => 0
)
),
),
[1]=> array(
[0] => array(
'id' => '32',
'section' => '',
'sorting' => '',
'title' => 'A. Risk Management',
'pdf_file' => '',
'content' => '',
'parent_id' => '0',
'isArray' => array(
[0] => array(
'id' => '33',
'section' => '911',
'sorting' => '',
'title' => 'RISK MANAGEMENT',
'pdf_file' => '',
'content' => '',
'parent_id' => '32',
'isArray' => array(
[0] => array(
'id' => '34',
'section' => 'ASDF',
'sorting' => '',
'title' => 'ASDFSDF',
'pdf_file' => '',
'content' => '',
'parent_id' => '33',
'isArray' = array()
)
)
)
)
)
)
)
And the data I get from the database is this
I came up with this code:
public function findParentsParent($result) {
global $subs;
foreach ($result as $row) {
$isArray = filter_var($row->isArray, FILTER_VALIDATE_BOOLEAN);
if ($isArray) {
$subs[][$row->parent_id] = $row;
$where = ['parent_id' => $row->id];
$result = $this->my_model->select_where('tbl_policies', $where, 'sorting, section');
if(!empty($result))
$this->findParentsParent($result);
//return array_reverse($subs);
} else {
$subs[] = $row;
}
}
return array_reverse($subs);
}
But I ended up with this array:
array(6) {
[0]=>
object(stdClass)#44 (11) {
["id"]=>
string(2) "30"
["section"]=>
string(3) "001"
["sorting"]=>
string(0) ""
["title"]=>
string(33) "Examination by the Bangko Sentral"
["pdf_file"]=>
string(41) "NRBSL CHRISTMAS PARTY RAFFLE WINNERS1.pdf"
["content"]=>
string(0) ""
["parent_id"]=>
string(2) "29"
["isArray"]=>
string(1) "0"
["uploaded_by"]=>
string(1) "6"
["created_at"]=>
string(19) "2022-03-03 11:46:06"
["updated_at"]=>
string(19) "2022-03-03 11:46:06"
}
[1]=>
object(stdClass)#43 (11) {
["id"]=>
string(2) "31"
["section"]=>
string(3) "002"
["sorting"]=>
NULL
["title"]=>
string(30) "Supervisory Enforcement Policy"
["pdf_file"]=>
string(13) "APL-Form1.pdf"
["content"]=>
string(0) ""
["parent_id"]=>
string(2) "29"
["isArray"]=>
string(1) "0"
["uploaded_by"]=>
string(1) "6"
["created_at"]=>
string(19) "2022-03-03 13:19:27"
["updated_at"]=>
string(19) "2022-03-03 13:19:27"
}
[2]=>
array(1) {
[0]=>
object(stdClass)#40 (11) {
["id"]=>
string(2) "29"
["section"]=>
string(0) ""
["sorting"]=>
string(0) ""
["title"]=>
string(28) "POWERS OF THE BANGKO SENTRAL"
["pdf_file"]=>
string(0) ""
["content"]=>
string(0) ""
["parent_id"]=>
string(1) "0"
["isArray"]=>
string(1) "1"
["uploaded_by"]=>
string(1) "6"
["created_at"]=>
string(19) "2022-03-03 11:45:25"
["updated_at"]=>
string(19) "2022-03-03 11:45:25"
}
}
[3]=>
array(1) {
[33]=>
object(stdClass)#42 (11) {
["id"]=>
string(2) "34"
["section"]=>
string(4) "ASDF"
["sorting"]=>
NULL
["title"]=>
string(7) "ASDFSDF"
["pdf_file"]=>
string(0) ""
["content"]=>
string(0) ""
["parent_id"]=>
string(2) "33"
["isArray"]=>
string(1) "1"
["uploaded_by"]=>
string(1) "6"
["created_at"]=>
string(19) "2022-03-04 09:29:37"
["updated_at"]=>
string(19) "2022-03-04 09:29:37"
}
}
[4]=>
array(1) {
[32]=>
object(stdClass)#41 (11) {
["id"]=>
string(2) "33"
["section"]=>
string(3) "911"
["sorting"]=>
NULL
["title"]=>
string(15) "RISK MANAGEMENT"
["pdf_file"]=>
string(0) ""
["content"]=>
string(0) ""
["parent_id"]=>
string(2) "32"
["isArray"]=>
string(1) "1"
["uploaded_by"]=>
string(1) "6"
["created_at"]=>
string(19) "2022-03-04 09:29:18"
["updated_at"]=>
string(19) "2022-03-04 09:29:18"
}
}
[5]=>
array(1) {
[0]=>
object(stdClass)#39 (11) {
["id"]=>
string(2) "32"
["section"]=>
NULL
["sorting"]=>
NULL
["title"]=>
string(18) "A. Risk Management"
["pdf_file"]=>
string(0) ""
["content"]=>
string(0) ""
["parent_id"]=>
string(1) "0"
["isArray"]=>
string(1) "1"
["uploaded_by"]=>
string(1) "6"
["created_at"]=>
string(19) "2022-03-04 09:28:41"
["updated_at"]=>
string(19) "2022-03-04 09:28:41"
}
}
}
Credits to Recursive function to generate multidimensional array from database result
I solved my problem with this code
public function buildTree(array $elements, $parentId = 0) {
$branch = array();
foreach ($elements as $element) {
if ($element['parent_id'] == $parentId) {
$children = $this->buildTree($elements, $element['id']);
$isArray = filter_var($element['isArray'], FILTER_VALIDATE_BOOLEAN);
if ($isArray) {
$element['isArray'] = $children;
}
$branch[] = $element;
}
}
return $branch;
}
I have the following array that I want to return as a single level so I can output it to a CSV. I need to keep the array keys. The arrays that are "children_data" I want to move to the same level as the parent array.
array(8) {
["id"]=>
int(2)
["parent_id"]=>
int(1)
["name"]=>
string(16) "Category 1"
["is_active"]=>
bool(true)
["position"]=>
int(1)
["level"]=>
int(1)
["product_count"]=>
int(1)
["children_data"]=>
array(3) {
[0]=>
array(8) {
["id"]=>
int(2380)
["parent_id"]=>
int(2)
["name"]=>
string(11) "subcat 1"
["is_active"]=>
bool(true)
["position"]=>
int(1)
["level"]=>
int(2)
["product_count"]=>
int(1)
["children_data"]=>
array(4) {
[0]=>
array(8) {
["id"]=>
int(2381)
["parent_id"]=>
int(2380)
["name"]=>
string(11) "subsub cat 1"
["is_active"]=>
bool(true)
["position"]=>
int(1)
["level"]=>
int(3)
["product_count"]=>
int(1)
["children_data"]=>
array(7) {
[0]=>
array(8) {
["id"]=>
int(2382)
["parent_id"]=>
int(2381)
["name"]=>
string(21) "subsubsub cat1"
["is_active"]=>
bool(true)
["position"]=>
int(1)
["level"]=>
int(4)
["product_count"]=>
int(1)
["children_data"]=>
array(19) {
[0]=>
array(8) {
["id"]=>
int(2383)
["parent_id"]=>
int(2382)
["name"]=>
string(12) "subsubssubsubb cat1"
["is_active"]=>
bool(true)
["position"]=>
int(1)
["level"]=>
int(5)
["product_count"]=>
int(0)
["children_data"]=>
array(4) {
[0]=>
array(8) {
["id"]=>
int(2384)
["parent_id"]=>
int(2383)
["name"]=>
string(13) "subsub1"
["is_active"]=>
bool(true)
["position"]=>
int(1)
["level"]=>
int(6)
["product_count"]=>
int(0)
["children_data"]=>
array(0) {
}
}
[1]=>
array(8) {
["id"]=>
int(2385)
["parent_id"]=>
int(2383)
["name"]=>
string(10) "subsub2"
["is_active"]=>
bool(true)
["position"]=>
int(2)
["level"]=>
int(6)
["product_count"]=>
int(0)
["children_data"]=>
array(0) {
}
}
What I need is:
array(8) {
["id"]=>
int(2)
["parent_id"]=>
int(1)
["name"]=>
string(16) "Category 1"
["is_active"]=>
bool(true)
["position"]=>
int(1)
["level"]=>
int(1)
["product_count"]=>
int(1)
array(8) {
["id"]=>
int(2380)
["parent_id"]=>
int(2)
["name"]=>
string(11) "subcat 1"
["is_active"]=>
bool(true)
["position"]=>
int(1)
["level"]=>
int(2)
["product_count"]=>
int(1)
array(8) {
["id"]=>
int(2381)
["parent_id"]=>
int(2380)
["name"]=>
string(11) "subsub cat 1"
["is_active"]=>
bool(true)
["position"]=>
int(1)
["level"]=>
int(3)
["product_count"]=>
int(1)
array(8) {
["id"]=>
int(2382)
["parent_id"]=>
int(2381)
["name"]=>
string(21) "subsubsub cat1"
["is_active"]=>
bool(true)
["position"]=>
int(1)
["level"]=>
int(4)
["product_count"]=>
int(1)
ETC
I need this to create a comparison between our Main DB categories and Magento categories. This way when we do a product import via the API, I can match the Magento category with our Main DB category.
There are a lot of good examples in the question linked by #waterloomatt, but that is a question that specifically asks "how to do this without using recursion".
The simplest way to turn your nested category tree into a flattened array is to use recursion:
function flatten($array, &$result) {
foreach ($array as $item) {
$children = $item['children_data'] ?? array();
unset($item['children_data']);
$result[] = $item;
flatten($children, $result);
}
}
$flattened = array();
flatten($categories, $flattened);
Note that this does require $categories to be an array that's nested one more level than your var_dump() sample data, so:
$categories = array(
0 => array(
"id" => 2,
"parent_id" => 1,
"name" => "Category 1",
"is_active" => true,
"position" => 1,
"level" => 1,
"product_count" => 1,
"children_data" => array(
0 => array(
"id" => 2380,
"parent_id" => 2,
...etc
This will give you the array you want, which you can then iterate over to output it into your CSV file:
var_export($flattened);
array (
0 =>
array (
'id' => 2,
'parent_id' => 1,
'name' => 'Category 1',
'is_active' => true,
'position' => 1,
'level' => 1,
'product_count' => 1,
),
1 =>
array (
'id' => 2380,
'parent_id' => 2,
'name' => 'subcat 1',
'is_active' => true,
'position' => 1,
'level' => 2,
'product_count' => 1,
),
2 =>
array (
'id' => 2381,
'parent_id' => 2380,
'name' => 'subsub cat 1',
'is_active' => true,
'position' => 1,
'level' => 3,
'product_count' => 1,
),
3 =>
array (
'id' => 2382,
'parent_id' => 2381,
'name' => 'subsubsub cat1',
'is_active' => true,
'position' => 1,
'level' => 4,
'product_count' => 1,
),
4 =>
array (
'id' => 2383,
'parent_id' => 2382,
'name' => 'subsubssubsubb cat1',
'is_active' => true,
'position' => 1,
'level' => 5,
'product_count' => 0,
),
5 =>
array (
'id' => 2384,
'parent_id' => 2383,
'name' => 'subsub1',
'is_active' => true,
'position' => 1,
'level' => 6,
'product_count' => 0,
),
6 =>
array (
'id' => 2385,
'parent_id' => 2383,
'name' => 'subsub2',
'is_active' => true,
'position' => 2,
'level' => 6,
'product_count' => 0,
),
)
I have an array like this. I want remove elements with duplicate id and get sum of the count
array(3) {
[0]=>
array(3) {
["Id"]=>
string(1) "1"
["Name"]=>
string(1) "a"
["Count"]=>
string(1) "2"
}
[1]=>
array(3) {
["Id"]=>
string(1) "2"
["Name"]=>
string(1) "b"
["Count"]=>
string(1) "1"
}[2]=>
array(3) {
["Id"]=>
string(1) "1"
["Name"]=>
string(1) "a"
["Count"]=>
string(1) "1"
}
}
and I need to remove elements with duplicate id and get sum of the count as shown below
array(2) {
[0]=>
array(3) {
["Id"]=>
string(1) "1"
["Name"]=>
string(1) "a"
["Count"]=>
string(1) "3"
}[1]=>
array(3) {
["Id"]=>
string(1) "2"
["Name"]=>
string(1) "b"
["Count"]=>
string(1) "1"
}
}
I have gone through many examples.. but couldn't find an answer..
Unfortunately there is no way around looping. Assuming that Name is the same for the same Id or that you don't care about the value of Name:
foreach($array as $value) {
if(!isset($result[$value['Id']])) {
$result[$value['Id']] = $value;
} else {
$result[$value['Id']]['Count'] += $value['Count'];
}
}
// re-index if needed
$result = array_values($result);
Loop the array and build result array using Id as key
If the key Id doesn't exist create it
If it does exist add Count to the current Count
just create a new array, loop through current, create if doesnt exist, and insert values (sum) into new one
what are you doing with duplicates names?
example below. hope it will help.
<?php
$tArr = array(
array(
"Id" => "1",
"Name" => "a",
"Count" => "2",
),
array(
"Id" => "2",
"Name" => "b",
"Count" => "1",
),
array(
"Id" => "1",
"Name" => "a",
"Count" => "1",
)
);
$rez = array();
foreach ($tArr as $key => $element) {
if (empty($rez[$element["Id"]])) {
$rez[$element["Id"]] = $element;
} else {
$rez[$element["Id"]]["Count"] += $element["Count"];
}
}
var_dump($rez);
/** array (size=2)
1 =>
array (size=3)
'Id' => string '1' (length=1)
'Name' => string 'a' (length=1)
'Count' => int 3
2 =>
array (size=3)
'Id' => string '2' (length=1)
'Name' => string 'b' (length=1)
'Count' => string '1' (length=1)**/
Try this
$result = array_diff_assoc($arr, array_unique($arr));
print_r($result);
I would like to create a JSON from Array in a specific way. My array looks like this at the beginning:
array(2) {
[22]=>
array(8) {
["factor"]=>
array(2) {
[0]=>
string(2) "12"
[1]=>
string(1) "1"
}
["unit"]=>
array(2) {
[0]=>
string(6) "months"
[1]=>
string(5) "times"
}
["value"]=>
array(2) {
[0]=>
string(3) "2.5"
[1]=>
string(1) "2"
}
["planid"]=>
array(2) {
[0]=>
string(1) "1"
[1]=>
string(1) "1"
}
["position"]=>
array(2) {
[0]=>
string(22) "Test 1"
[1]=>
string(21) "Test 2"
}
["vouchervalue"]=>
array(2) {
[0]=>
string(1) "0"
[1]=>
string(1) "0"
}
["vouchertype"]=>
array(2) {
[0]=>
string(0) ""
[1]=>
string(0) ""
}
["vat"]=>
array(2) {
[0]=>
int(19)
[1]=>
int(19)
}
}
[23]=>
array(8) {
["factor"]=>
array(2) {
[0]=>
string(2) "12"
[1]=>
string(1) "1"
}
["unit"]=>
array(2) {
[0]=>
string(6) "months"
[1]=>
string(5) "times"
}
["value"]=>
array(2) {
[0]=>
string(3) "2.5"
[1]=>
string(1) "2"
}
["planid"]=>
array(2) {
[0]=>
string(1) "1"
[1]=>
string(1) "1"
}
["position"]=>
array(2) {
[0]=>
string(22) "Test 3"
[1]=>
string(21) "Test 4"
}
["vouchervalue"]=>
array(2) {
[0]=>
string(1) "0"
[1]=>
string(1) "0"
}
["vouchertype"]=>
array(2) {
[0]=>
string(0) ""
[1]=>
string(0) ""
}
["vat"]=>
array(2) {
[0]=>
int(19)
[1]=>
int(19)
}
}
}
This is how the JSON looks like:
string(354) "{"factor":[["12","1"],["12","1"]],"unit":[["months","times"],["months","times"]],"value":[["2.5","2"],["2.5","2"]],"planid":[["1","1"],["1","1"]],"position":[["Test 1","Test 2"],["Test 3","Test 4"]],"vouchervalue":[["0","0"],["0","0"]],"vouchertype":[["",""],["",""]],"vat":[[19,19],[19,19]]}"
But I would like to have it this way:
string(214) "{"factor":["12", "1","12","1"],"unit":["months", "times","months","times"],"value":["2.5","2","2.5", "2"],"planid":["1","1","1","1"],"position":["Test 1","Test 2", "Test 3", "Test 4"],"vouchervalue":["0","0","0","0"],"vouchertype":["","","",""],"vat":[19,19,19,19]}"
The idea is that every order can contain more than 1 position that can be used to create a JSON which can be used in the rest of the application (there is a table that uses JSON).
Well, I've no idea how to solve this so I'm happy about any hint :-)
Let us say you have the data in array $a.
$a = array(
array(
'factor'=> array( '12', '1' ),
'unit'=> array( 'months', 'times' ),
'value'=> array( '2.5', '2' ),
'planid'=> array( '1', '1' ),
'position'=> array( 'Test 1', 'Test 2' ),
'vouchervalue'=> array( '0', '0' ),
'vouchertype'=> array( '', '' ),
'vat'=> array( 19, 19 ),
),
array(
'factor'=> array( '12', '1' ),
'unit'=> array( 'months', 'times' ),
'value'=> array( '2.5', '2' ),
'planid'=> array( '1', '1' ),
'position'=> array( 'Test 3', 'Test 4' ),
'vouchervalue'=> array( '0', '0' ),
'vouchertype'=> array( '', '' ),
'vat'=> array( 19, 19),
),
);
This in your example contains two arrays, you want to combine. This is one way:
$b = array();
foreach( $a[0] as $k=>$v ) {
if ( isset( $a[1][$k] ) ) // Add keys in both arrays
$b[$k] = array_merge( $a[0][$k], $a[1][$k] );
else // Add keys in only first array
$b[$k] = $a[0][$k];
}
foreach( $a[1] as $k=>$v ) {
if ( !isset( $a[0][$k] ) ) // Add keys in only second array
$b[$k] = $a[1][$k];
}
echo json_encode( $b );
This iterates through the first array. If the key ('factor', 'unit') is available in both arrays, it merges them otherwise it just adds the array.
Secondly it iterates through the second array and adds the arrays which has not been added in the first pass (if the key was not in the first array).
In your case, the arrays seem to have the same set of keys, and a second pass might not be necessary, but just to be sure...
This is the result:
{"factor":["12","1","12","1"],"unit":["months","times","months","times"],"value":["2.5","2","2.5","2"],"planid":["1","1","1","1"],"position":["Test 1","Test 2","Test 3","Test 4"],"vouchervalue":["0","0","0","0"],"vouchertype":["","","",""],"vat":[19,19,19,19]}
If you do not want the numbers in the json to be string encoded, like "12" but rather 12, add JSON_NUMERIC_CHECK to json_encode
echo json_encode( $b, JSON_NUMERIC_CHECK );
{"factor":[12,1,12,1],"unit":["months","times","months","times"],"value":[2.5,2,2.5,2],"planid":[1,1,1,1],"position":["Test 1","Test 2","Test 3","Test 4"],"vouchervalue":[0,0,0,0],"vouchertype":["","","",""],"vat":[19,19,19,19]}
You're looking for array_merge_recursive(). Per the docs:
array_merge_recursive() merges the elements of one or more arrays together so that the values of one are appended to the end of the previous one. It returns the resulting array.
If the input arrays have the same string keys, then the values for these keys are merged together into an array, and this is done recursively, so that if one of the values is an array itself, the function will merge it with a corresponding entry in another array too. If, however, the arrays have the same numeric key, the later value will not overwrite the original value, but will be appended.
Using the example inputs that #HasseBjork outlined above in his answer (based on your original input):
$a = array(
array(
'factor'=> array( '12', '1' ),
'unit'=> array( 'months', 'times' ),
'value'=> array( '2.5', '2' ),
'planid'=> array( '1', '1' ),
'position'=> array( 'Test 1', 'Test 2' ),
'vouchervalue'=> array( '0', '0' ),
'vouchertype'=> array( '', '' ),
'vat'=> array( 19, 19 ),
),
array(
'factor'=> array( '12', '1' ),
'unit'=> array( 'months', 'times' ),
'value'=> array( '2.5', '2' ),
'planid'=> array( '1', '1' ),
'position'=> array( 'Test 3', 'Test 4' ),
'vouchervalue'=> array( '0', '0' ),
'vouchertype'=> array( '', '' ),
'vat'=> array( 19, 19),
),
);
All you need to do is:
echo json_encode(array_merge_recursive($a[0], $a[1]));