PHP looping recursive function - php

I had this looping function and what it does to fetch data then display the result in json format. In $subArray[] i try to call the looping function again so it can read if got any sub-nodes underneath. But seem the result not display as I expected to be.
function recursiveNode($ledgerID,$accountID){
global $ehorsObj;
$subArray = array();
$query_get_subchild = " SELECT accountLedgerID, accountID, accountMainID, accountName, active
FROM tblAccAccounts
WHERE accountMain = 'y'
AND accountSub = 'y'
AND accountMainID = '".$accountID."'
AND accountLedgerID = '".$ledgerID."'
ORDER BY accountName
";
$GetResult = $ehorsObj->FetchData($query_get_subchild, $ehorsObj->DEFAULT_PDO_CONNECTIONS);
while ($row3 = $GetResult->fetch()) {
$subArray[] = array('accountLedgerID' => $row3['accountLedgerID'], 'accountID' => $row3['accountID'], 'accountMainID' => $row3['accountMainID'], 'accountName' => $row3['accountName'], 'active' => $row3['active'], 'items' => recursiveNode($ledgerID, $row3['accountID']));
}
header("Content-type: application/json");
$result = json_encode($subArray);
echo $result;
}
it show the result (as image below)
and the result I expected to be like this
[
{
accountLedgerID: "LA1",
accountID: "LA95",
accountMainID: "LA5",
accountName: "SubGroup RunDeposit 1",
active: "y"
},
{
accountLedgerID: "LA1",
accountID: "LA2",
accountMainID: "LA5",
accountName: "SubGroup RunDeposit 2",
active: "y",
item: [
{
accountLedgerID: "LA1",
accountID: "LA125",
accountMainID: "LA2",
accountName: "Sub x2 Group RunDeposit 2",
active: "y",
items: [
{
accountLedgerID: "LA1",
accountID: "LA6",
accountMainID: "LA125",
accountName: "Sub x3 Group RunDeposit 2",
active: "y",
items: [ ]
}
]
}
]
}
]

function fetch_account ($dbresult, $ledgerID, $accountID) {
$result = array_filter($dbresult, function ($something) use ($ledgerID, $accountID) {
if ( $something['accountMainID'] == $accountID && $something['accountLedgerID'] == $ledgerID ) {
return true;
}
return false;
});
return array_values($result);
}
function recursiveNode($ledgerID,$accountID){
$testArray = [
[
'accountLedgerID' => 'LA1',
'accountID' => 'LA95',
'accountMainID' => 'LA5',
'accountName' => 'SubGroup RunDeposit 1',
'active' => 'y'
],
[
'accountLedgerID' => 'LA1',
'accountID' => 'LA2',
'accountMainID' => 'LA5',
'accountName' => 'SubGroup RunDeposit 2',
'active' => 'y'
],
[
'accountLedgerID' => 'LA1',
'accountID' => 'LA125',
'accountMainID' => 'LA2',
'accountName' => 'Sub x2 Group RunDeposit 2',
'active' => 'y'
],
[
'accountLedgerID' => 'LA1',
'accountID' => 'LA6',
'accountMainID' => 'LA125',
'accountName' => 'Sub x3 Group RunDeposit 2',
'active' => 'y'
]
];
$someArray = fetch_account($testArray, $ledgerID, $accountID);
$subArray = array();
$i = 0;
while (!empty($someArray[$i]) && $row3 = $someArray[$i]) {
$subArray[] = array(
'accountLedgerID' => $row3['accountLedgerID'],
'accountID' => $row3['accountID'],
'accountMainID' => $row3['accountMainID'],
'accountName' => $row3['accountName'],
'active' => $row3['active'],
'items' => recursiveNode($ledgerID, $row3['accountID'])
);
$i++;
}
return $subArray;
}
$myArray = recursiveNode('LA1', 'LA5');
$result = json_encode($myArray);
echo $result;

Breaking down the problem first, I think the recursive function isn't returning anything. I think this is indicative when your result has 'items' as null.

Related

How to recursively sort associative array

I'd like to sort the following associative array:
$tree = [
"id" => 245974,
"children" => [
[
"id" => 111
],
[
"id" => 245982,
"children" => [
[
"id" => 246093,
"children" => [
[
"id" => 225892
],
[
"id" => 225893
],
[
"id" => 225902
]
]
]
]
]
]
];
Desired sort order after the "search value" of id => 225902:
[
"id" => 245974,
"children" => [
[
"id" => 245982, // <-- this is moved up
"children" => [
[
"id" => 246093,
"children" => [
[
"id" => 225902 // <-- this is moved up
],
[
"id" => 225892
],
[
"id" => 225893
]
]
]
]
],
[
"id" => 111
]
]
];
What I've tried:
<?php
$category_id = 225902;
function custom_sort(&$a, &$b) {
global $category_id;
if ($a['id'] === $category_id) {
return -1;
}
if ($b['id'] === $category_id) {
return 1;
}
if (array_key_exists('children', $a)) {
if (usort($a['children'], "custom_sort")) {
return -1;
}
}
if (array_key_exists('children', $b)) {
if (usort($b['children'], "custom_sort")) {
return 1;
}
}
return 0;
}
function reorder_tree($tree) {
usort($tree['children'], "custom_sort");
return $tree;
}
echo "<pre>";
var_dump(reorder_tree($tree));
echo "</pre>";
However, that returns:
[
"id" => 245974,
"children" => [
[
"id" => 245982, // <- this is moved up
"children" => [
[
"id" => 246093,
"children" => [
[
"id" => 225892
],
[
"id" => 225893
],
[
"id" => 225902 // <- this is *not* moved up
]
]
]
]
],
[
"id" => 111
],
]
];
How would I be able to also sort the children arrays?
Great attempt and very much on the right track. The problem with recursion in the comparator is that usort will not call the comparator function when the array length is 1, so whether or not you explore the whole tree is at the whim of usort. This will abandon id => 245982's branch of the tree.
The solution is to avoid recursing in the usort's comparator function directly. Rather, use a regular recursive function that calls usort as needed, namely, the current array or a child array contains the target id. I use a separate array to keep track of which elements should be moved forward, but you can break out of the loop and splice/unshift a single element to the front if you prefer.
We can also make $category_id a parameter to the function.
Here's one approach:
function reorder_tree_r(&$children, $target) {
$order = [];
$should_sort = false;
foreach ($children as $i => &$child) {
$order[$i] = false;
if (array_key_exists("children", $child) &&
reorder_tree_r($child["children"], $target) ||
$child["id"] === $target) {
$order[$i] = true;
$should_sort = true;
}
}
if ($should_sort) {
$priority = [];
$non_priority = [];
for ($i = 0; $i < count($children); $i++) {
if ($order[$i]) {
$priority[]= $children[$i];
}
else {
$non_priority[]= $children[$i];
}
}
$children = array_merge($priority, $non_priority);
}
return $should_sort;
}
function reorder_tree($tree, $target) {
if (!$tree || !array_key_exists("children", $tree)) {
return $tree;
}
reorder_tree_r($tree["children"], $target);
return $tree;
}
var_export(reorder_tree($tree, 225902));
Output:
array (
'id' => 245974,
'children' =>
array (
0 =>
array (
'id' => 245982,
'children' =>
array (
0 =>
array (
'id' => 246093,
'children' =>
array (
0 =>
array (
'id' => 225902,
),
1 =>
array (
'id' => 225892,
),
2 =>
array (
'id' => 225893,
),
),
),
),
),
1 =>
array (
'id' => 111,
),
),

Array manipulation: Convert one array to another

For a few hours, I lost myself in an array.
I have something like this:
$results = [
"User_1" = [
"Step_1" = "accepted",
"Step_2" = "accepted",
"Step_3" = "waiting",
"Step_4" = "refused"
],
"User_2" = [
"Step_1" = "waiting",
"Step_2" = "accepted",
"Step_3" = "accepted",
"Step_4" = "refused"
],
];
I need to count (and have the sum) of all the "status" for a specific "Step".
In this case, I wish to have :
$steps = [
"Step_1" = [
'acceptedSum' => 1,
'refusedSum' => 0,
'waitingSum' => 1
],
"Step_2" =[
'acceptedSum' => 2,
'refusedSum' => 0,
'waitingSum' => 0
],
"Step_3" =[
'acceptedSum' => 1,
'refusedSum' => 0,
'waitingSum' => 1
],
"Step_4" =[
'acceptedSum' => 0,
'refusedSum' => 0,
'waitingSum' => 2
],
];
[ Nota: Number of User is not defined (1 to N) and number of Step too (1 to 4) ]
Any help will be appreciated :)
Thanks to you.
Try this, see if it works or not.
$steps = array();
$count = 0;
$keys = array_keys(current($results));
foreach($keys as $key){
$accepted = 0;
$refused = 0;
$waiting = 0;
foreach ($results as $result) {
foreach ($result as $k => $v) {
if ($key==$k&&$v == 'accepted') {
$accepted++;
}
if ($key==$k&&$v == 'refused') {
$refused++;
}
if ($key==$k&&$v == 'accepted') {
$waiting++;
}
}
}
$new_array = [
'acceptedSum' => $accepted,
'refusedSum' => $refused,
'withoutAnswerSum' => $waiting
];
$steps[$key] = $new_array;
}
print_r($steps);
You could create the existing keys dynamically. The missing keys you could add with a value of 0;
$results = [
"User_1" => [
"Step_1" => "accepted",
"Step_2" => "accepted",
"Step_3" => "waiting"
],
"User_2" => [
"Step_1" => "waiting",
"Step_2" => "accepted",
"Step_3" => "accepted"
],
"User_3" => [
"Step_1" => "refused",
"Step_2" => "refused",
"Step_3" => "waiting"
]
];
$steps = [];
$status = [];
foreach ($results as $result) {
foreach ($result as $key => $r) {
if (!array_key_exists($key, $steps)) {
$steps[$key] = [];
}
if (!array_key_exists($r."Sum", $steps[$key])) {
$steps[$key][$r."Sum"] = 0;
}
$steps[$key][$r."Sum"]++;
$status[] = $r;
}
}
foreach (array_unique($status) as $au) {
foreach ($steps as &$step) {
if (!array_key_exists($au."Sum", $step)) {
$step[$au."Sum"] = 0;
}
}
}
print_r($steps);
Php output demo
I think the output in your question is wrong, but are you looking for something like this
<?php
$results = [
"User_1" => [
"Step_1" => "accepted",
"Step_2" => "accepted",
"Step_3" => "waiting"
],
"User_2" => [
"Step_1" => "waiting",
"Step_2" => "accepted",
"Step_3" => "accepted"
],
"User_3" => [
"Step_1" => "refused",
"Step_2" => "refused",
"Step_3" => "waiting"
]
];
function sumByStatus($array, $status) {
$filtered_array = array_filter($array,function($value) use ($status) {
return $value === $status;
});
return count($filtered_array);
}
$newResult = array_map(function($item) {
return [
'acceptedSum' => sumByStatus($item, 'accepted'),
'refusedSumF' => sumByStatus($item, 'refused'),
'withoutAnswerSum' => sumByStatus($item, 'waiting')
];
}, $results);
print_r($newResult);
The output is
Array
(
[User_1] => Array
(
[acceptedSum] => 2
[refusedSum] => 0
[withoutAnswerSum] => 1
)
[User_2] => Array
(
[acceptedSum] => 2
[refusedSum] => 0
[withoutAnswerSum] => 1
)
[User_3] => Array
(
[acceptedSum] => 0
[refusedSum] => 2
[withoutAnswerSum] => 1
)
)

Group subarray data by one column and form comma-separated values from the secondary value in each group [duplicate]

This question already has answers here:
Group subarrays by one column, make comma-separated values from other column within groups
(2 answers)
Closed last month.
I have a two dimensional array which needs to be restructured. Rows must be grouped by date values, and within each group, the name values should be formed into a single comma-delimited string.
My input:
$missedFridgeLog = [
[
"date" => "01/01/18",
"name" => "Medicine"
],
[
"date" => "01/01/18",
"name" => "Drugs"
],
[
"date" => "02/01/18",
"name" => "Medicine"
],
[
"date" => "02/01/18",
"name" => "Drugs"
]
];
I have tried implementing a solution from Implode or join multidimentional array with comma, but it did not work as desired.
Desired output:
[
[
'date' => '01/01/18',
'name' => 'Medicine,Drugs',
],
[
'date' => '02/01/18',
'name' => 'Medicine,Drugs',
]
]
$missedFridgeLog = [
[
"date" => "01/01/18",
"name" => "Medicine"
],[
"date" => "01/01/18",
"name" => "Drugs"
]
[
"date" => "02/01/18",
"name" => "Medicine"
],
[
"date" => "02/01/18",
"name" => "Drugs"
]
];
$byDates = [];
foreach ($missedFridgeLog as $mfg) {
$byDates[$mfg['date']][] = $mfg['name'];
}
$res = [];
foreach ($byDates as $date => $name) {
$res[] = [
'name' => join(',',$name),
'date' => $date
];
}
var_dump($res);
You need to search key, value pair everytime you make a insert or update to result array. use this function() to search associate array. If match then update with additional name info else make a new insert to result array.
function filter_array($array){
///$array your previous array data
$result = array();
foreach($array["missedFridgeLog"] as $m){
$flag = true;
foreach($result as $k=>$r) {
if (is_in_array($r, "date", $m["date"]) == "yes") {
$result[$k]["name"] = $r["name"] . ',' . $m["name"];
$flag = false;
break;
}
}
if($flag==true){
$result[] = $m;
}
}
return array("missedFridgeLog"=>$result);
}
function is_in_array($array, $key, $key_value){
$within_array = 'no';
foreach( $array as $k=>$v ){
if( is_array($v) ){
$within_array = is_in_array($v, $key, $key_value);
if( $within_array == 'yes' ){
break;
}
} else {
if( $v == $key_value && $k == $key ){
$within_array = 'yes';
break;
}
}
}
return $within_array;
}
May be this is not the best way to do this, but it will help
$arr['missedFridgeLog'] = [
[
'date' => '01/01/18',
'name' => 'Medicine1'
],
[
'date' => '02/01/18',
'name' => 'New Medicine2'
],
[
'date' => '01/01/18',
'name' => 'Drugs1'
],
[
'date' => '02/01/18',
'name' => 'Medicine2'
],
[
'date' => '01/01/18',
'name' => 'New Drugs1'
],
[
'date' => '02/01/18',
'name' => 'Drugs2'
]
];
echo "<pre>";
$new_arr = array();
$date = array();
foreach ($arr['missedFridgeLog'] as $k => $a) {
if (in_array($a['date'], $date))
continue;
$new_arr[$k]['name'] = $a['name'];
$new_arr[$k]['date'] = "";
foreach ($arr[missedFridgeLog] as $key => $val) {
if ($key != $k) {
if ($a['date'] == $val['date']) {
$date[] = $new_arr[$k]['date'] = $a['date'];
$new_arr[$k]['name'] .= ", " . $val['name'];
}
}
}
if (empty($new_arr[$k]['date']))
unset($new_arr[$k]);
}
print_r($new_arr);
You can try below :-
Input array :-
$chkArray = [
'missedFridgeLog' => [
'0' => [
'date' => '01/01/18',
'name' => 'Medicine'
],
'1' => [
'date' => '01/01/18',
'name' => 'Drugs'
],
'2' => [
'date' => '02/01/18',
'name' => 'Medicine'
],
'3' => [
'date' => '02/01/18',
'name' => 'Drugs'
],
'4' => [
'date' => '02/01/18',
'name' => 'My Drugs'
]
]
];
$i = 0;
$finalarray = array();
foreach($chkArray['missedFridgeLog'] as $key=>$value) {
$checkExist = array_search($value['date'], array_column($finalarray, 'date'), true);
if($checkExist !== false) {
$finalarray[$checkExist]['name'] = $finalarray[$checkExist]['name'].','.$value['name'];
}
else {
$finalarray[$i]['date'] = $value['date'];
$finalarray[$i]['name'] = $value['name'];
$i++;
}
}
print_r($finalarray);
OutPut :-
Array
(
[0] => Array
(
[date] => 01/01/18
[name] => Medicine,Drugs
)
[1] => Array
(
[date] => 02/01/18
[name] => Medicine,Drugs,My Drugs
)
)
Do not use:
More than one loop,
Nested loops,
in_array(), or
array_search().
You only need one loop to apply temporary grouping keys. When a date/group is encountered after the first time, append its name value to the group's name value. When finished iterating, re-index the array.
Code: (Demo)
$result = [];
foreach ($missedFridgeLog as $row) {
if (!isset($result[$row['date']])) {
$result[$row['date']] = $row;
} else {
$result[$row['date']]['name'] .= ",{$row['name']}";
}
}
var_export(array_values($result));
Output:
array (
0 =>
array (
'date' => '01/01/18',
'name' => 'Medicine,Drugs',
),
1 =>
array (
'date' => '02/01/18',
'name' => 'Medicine,Drugs',
),
)

Array Operations to add / remove entries from 1 to another

I have 2 sets of array:
Data:
$data = [
[
'company_code' => 'ABC',
'supplier_codes' => [
'S-2',
'S-3',
'S-5',
],
],
];
Source (from database):
$database = [
'company_code' => 'ABC',
'suppliers' => [
[
'code' => 'S-1',
],
[
'code' => 'S-2',
'reference' => '12345'
],
[
'code' => 'S-3',
],
[
'code' => 'S-4',
'reference' => 'some string',
]
],
];
What I need to achieve:
If a supplier code is missing in $data but exists in $database,
remove it from $database.
If a supplier code exists in $data but missing in $database, add it into $database
The output of the example here should be as follows:
$output = [
'company_code' => 'ABC',
'suppliers' => [
[
'code' => 'S-2',
'reference' => '12345'
],
[
'code' => 'S-3',
],
[
'code' => 'S-5',
]
],
];
I was thinking of removing the suppliers subarray, then reconstruct the structure based on the data from supplier_codes. But the problem is some of the entries in suppliers may have an optional field called reference.
Try this
<?php
$data = [
[
'company_code' => 'ABC',
'supplier_codes' => ['S-2','S-3','S-5'],
],
];
$database = [
'company_code' => 'ABC',
'suppliers' => [
[
'code' => 'S-1',
],
[
'code' => 'S-2',
'reference' => '12345'
],
[
'code' => 'S-3',
],
[
'code' => 'S-4',
'reference' => 'some string',
]
],
];
foreach($database['suppliers'] as $k=>$v){
foreach($data as $kd=>$vd){
$valueremove = false;
$removeIndex = '';
foreach($vd['supplier_codes'] as $key=>$val){
if($val == $v['code']){
$valueremove = false;
$removeIndex = '';
break;
} else {
$valueremove = true;
$removeIndex = $k;
}
}
if($valueremove == true){
unset($database['suppliers'][$removeIndex]);
} else {
$valueinsert = false;
foreach($data as $kd=>$vd){
foreach($vd['supplier_codes'] as $key=>$val){
foreach($database['suppliers'] as $kc=>$vc){
if($val == $vc['code']){
$valueinsert = false;
$insertIndex = '';
$insertVal = '';
break;
} else {
$valueinsert = true;
$insertIndex = count($database['suppliers'])+1;
$insertVal = $val;
}
}
if($valueinsert == true){
$database['suppliers'][$insertIndex] = array('code'=>$insertVal);
}
}
}
}
}
}
echo "<PRE>"; print_r($database);
I end up solving my problem this way:
$result = $database;
$result['suppliers'] = [];
foreach($data as $tag) {
foreach($tag['supplier_codes'] as $code) {
$found = false;
foreach($database['suppliers'] as $supplier) {
if($supplier['code'] === $code) {
$result['suppliers'][] = $supplier;
$found = true;
}
}
if(!$found) {
$result['suppliers'][] = ['code' => $code];
}
}
}
Output of print_r($result);:
Array
(
[company_code] => ABC
[suppliers] => Array
(
[0] => Array
(
[code] => S-2
[reference] => 12345
)
[1] => Array
(
[code] => S-3
)
[2] => Array
(
[code] => S-5
)
)
)

How to get the sum in my collection in nested array?

I have this collection :
...
"votes": [
{
"track1": [
{
"facebook": NumberLong(1)
}
],
"track2": [
{
"google": NumberLong(1),
"twitter": NumberLong(1)
}
]
}
],
...
I want to get the sum of the votes of track1 or track2 so what i did is :
$match = array(
'app_id' => (int)$appId,
'campaign_id' => (int)$campaign_id
);
$group = array(
'_id' => 'votes.0.'.$_t.'.0.facebook', //$_t => track id
'total' => array(
'$sum' => '$votes.0.'.$_t.'.0.facebook'
)
);
$res = $collection->aggregate(array(
array(
'$match' => $match
),
array(
'$group' => $group
)
)
);
$res_facebook = (int) $res['result'][0]['total'];
Result : 0
Where is the problem ?
Not sure if it will work, I didn't check it, but I had something similar.
This is how I would solve it:
$votes_array = json_decode($votes_array_json,TRUE);
$total_votes = 0;
foreach($votes_array as $track) {
foreach($track as $social_network => $votes) {
$total_votes = $total_votes + $votes;
};
};

Categories