Reputation: 4047
hey there I've been trying to solve this for about 3 days now with no avail.
I have a 2d array that looks like:
$testObject = array(
array(
"id"=> 1,
"parentID"=> 0,
"insuCount"=> 300,
"totalInsuCount"=> '',
"childrenCount" => ''
),
array(
"id"=> 21,
"parentID"=> 1,
"insuCount"=> 136,
"totalInsuCount"=> '',
"childrenCount" => ''
),
array(
"id"=> 52,
"parentID"=> 21,
"insuCount"=> 99,
"totalInsuCount"=> '',
"childrenCount" => ''
)
);
The array has a children/parent it also has insuCount, totalInsuCount, childrenCount. i am trying to add up the issuCount from bottom of the hierarchy to the top parent and set the result in totalInsuCount,
Also it will count nested children, like the top parent in my situation has 2 children.
So basically my correct array should look something like:
$testObject = array(
array(
"id"=> 1,
"parentID"=> 0,
"insuCount"=> 300,
"totalInsuCount"=> 535,
"childrenCount" => 2
),
array(
"id"=> 21,
"parentID"=> 1,
"insuCount"=> 136,
"totalInsuCount"=> 235,
"childrenCount" => 1
),
array(
"id"=> 52,
"parentID"=> 21,
"insuCount"=> 99,
"totalInsuCount"=> 300,
"childrenCount" => 0
)
);
Anyone has a clue how would i do that, I've been at it for about 3 days now cant figure out how.
Thanks in advanced.
Upvotes: 0
Views: 903
Reputation: 109547
Mind I have outgrown PHP. So the following is simplistic code.
So:
$todo = array(); // Array of indices into $testObject.
for ($i = 0; $i < count($testObject); ++$i) {
$todo[] = $i;
}
while (count($todo) > 0) {
$didOne = FALSE;
foreach ($todo as $i) {
$id = $testObject[$i]["id"];
$isAtBottom = TRUE;
foreach ($todo as $j) {
if ($j != $i && $testObject[$j]["parentID"] == $id) {
$isAtBottom = FALSE;
break;
}
}
if ($isAtBottom) {
$didOne = TRUE;
$testObject[$i]["totalInsuCount"] = $testObject[$i]["insuCount"];
$testObject[$i]["childrenCount"] = 0;
for ($k = 0; $k < count($testObject); ++$k) { // Walk done items
if ($testObject[$k]["id"] != $id
&& $testObject[$k]["parentID"] == $id) {
$testObject[$i]["totalInsuCount"] +=
$testObject[$k]["totalInsuCount"];
++$testObject[$i]["childrenCount"];
}
}
array_splice($todo, $i, 1);
//break; // As $todo changed, simply next while
}
}
if (!$didOne) {
error_log("Cyclic dependency");
}
}
print("<pre>\n");
print_r($testObject);
print("\n</pre>\n");
Upvotes: 1
Reputation: 4984
First you have to transform your array into array with keys equal to your IDs. It will allow you to access any element directly by ID:
$testObject = array(
1 => array(
"id"=> 1,
"parentID"=> 0,
"insuCount"=> 300,
"totalInsuCount"=> '',
"childrenCount" => ''
),
21 => array(
"id"=> 21,
"parentID"=> 1,
"insuCount"=> 136,
"totalInsuCount"=> '',
"childrenCount" => ''
),
52 => array(
"id"=> 52,
"parentID"=> 21,
"insuCount"=> 99,
"totalInsuCount"=> '',
"childrenCount" => ''
)
);
this is pretty obvious to implement. So i will leave the solution to you.
And now we can easily calculate counts for all parents:
foreach ($testObject as $id => &$data){
$parentId = $data['parentID'];
while ($parentId && isset($testObject[$parentId])){
$parentData = &$testObject[$parentId];
$parentData["childrenCount"]++;
$parentData["totalInsuCount"] += $data["insuCount"];
$parentId = $parentData['parentID'];
}
$data["totalInsuCount"] += $data["insuCount"];
}
print_r($testObject);
UPDATE
Test that any children was counted and belongs to some root entry:
$totalChildren = 0;
foreach ($testObject as $data){
//sum all childrens of root elements
if (!$data['parentID']) $totalChildren += $data["childrenCount"] + 1;
}
echo 'Children counted: ' .$totalChildren;
echo "<br>";
echo 'Total elements: ' .sizeof($testObject);
Also i had to prepare the initial array as some entries are self referenced:
$newTestObject = array();
foreach ($testObject as $data){
if ($data['id'] == $data['parentID']) $data['parentID'] = 0;
$newTestObject[$data['id']] = $data;
}
$testObject = $newTestObject;
Upvotes: 1
Reputation: 2541
It kinda bugs me that I can't just write comments... anyway.
Your last array entry doesn't make sense to me. count = 99 + 0 children values = 300? How should the count work?
Upvotes: 0