This question already has answers here:
How to array_merge_recursive() an array?
(2 answers)
Closed 3 months ago.
I have an array like this:
[
{
"function_1": {
"element": {
"error": "0",
"msg": "test"
}
}
},
{
"function_1": {
"element_2": {
"error": "0",
"msg": "test"
}
}
},
{
"function_2": {
"element": {
"error": "0",
"msg": "test"
}
}
},
{
"function_2": {
"element_2": {
"error": "0",
"msg": "test"
}
}
}
]
I want output like this:
[
{
"function_1": {
"element": {
"error": "0",
"msg": "test"
},
"element_2": {
"error": "0",
"msg": "test"
}
}
},
{
"function_2": {
"element": {
"error": "0",
"msg": "test"
},
"element_2": {
"error": "0",
"msg": "test"
}
}
}
]
The answers that I found offered to search by name("function_1", "function_2"). But this does not suit me, the function will not always pass an array. I need exactly the "depth" or any other reasonable way.
Thank you!
To achieve your desired result, you could json-decode, recursively merge each individual subarray, then loop over that structure to push each item as a second-level array like this: (Demo)
$array = json_decode($json, true);
$merged = array_merge_recursive(...$array);
$result = [];
foreach ($merged as $key => $data) {
$result[] = [$key => $data];
}
var_export($result);
But I can't imagine getting any benefit from adding unnecessary depth to your result array. I recommend simply json decoding, then calling array_merge_recursive() with the spread operator: (Demo)
var_export(
array_merge_recursive(
...json_decode($json, true)
)
);
Output:
array (
'function_1' =>
array (
'element' =>
array (
'error' => '0',
'msg' => 'test',
),
'element_2' =>
array (
'error' => '0',
'msg' => 'test',
),
),
'function_2' =>
array (
'element' =>
array (
'error' => '0',
'msg' => 'test',
),
'element_2' =>
array (
'error' => '0',
'msg' => 'test',
),
),
)
Your data structure looks weird for the purpose you are trying to achieve I'm bored af tho and created this code for you
function combineElementsPerfunction($functions) {
$result = [];
$uniqueFunctions = [];
foreach ($functions as $function) {
$functionName = array_keys($function)[0];
$uniqueFunctions[] = $functionName;
}
$uniqueFunctions = array_unique($uniqueFunctions);
foreach ($uniqueFunctions as $uniqueFunction) {
$functionObjects = array_filter(
$functions,
function($function) use ($uniqueFunction) {
$functionName = array_keys($function)[0];
return $functionName === $uniqueFunction;
}
);
$elements = [];
foreach ($functionObjects as $functionObject) {
$function = array_shift($functionObject);
$elements = array_merge($elements, $function);
}
$result[] = [
$uniqueFunction => $elements
];
}
return $result;
}
function changeArr($data){
$box = $new = [];
foreach ($data as $v){
$key = array_key_first($v);
$i = count($box);
if(in_array($key, $box)){
$keys = array_flip($box);
$i = $keys[$key];
}else{
$box[] = $key;
}
$new[$i][$key] = isset($new[$i][$key]) ? array_merge($new[$i][$key], $v[$key]) : $v[$key];
}
return $new;
}
Related
I have the code below, but the result of the json response doesn't match
public function tes_get(){
$kode= $this->M_mymodel->tbl_kode('302'); // row
$res = array();
foreach ($kode as $key=> $value) {
$win = $this->M_mymodel->db_aa('302'); //row_array
$res = $this->M_mymodel->db_bb('302','LOSE'); //row_array
$res['data'][] = array(
'win' => $win['menang'],
'lose' =>$res['kalah']
);
}
$response = $this->set_response($res,200);
}
Below is the result of the response from the code I made above
{
"data": [
{
"win": "2",
"lose": "11"
}
]
}
How to make json response like below?
{
"data": [
{
"win": "2",
}
{
"lose": "11"
}
]
}
You can try :
$res['data'][] = array(
array('win' => $win['menang']),
array('lose' =>$res['kalah'])
);
[
{
"id": 1573695284631,
"name": "Cars",
"pid": 0,
"children": [
{
"id": 1573695292010,
"name": "Audi",
"pid": 1573695284631
},
{
"id": 1573695305619,
"name": "BMW",
"pid": 1573695284631,
"children": [
{
"id": 1573695328137,
"name": "3 Series",
"pid": 1573695305619
},
{
"id": 1573695335102,
"name": "X5",
"pid": 1573695305619
}
]
}
]
},
{
"id": 1573695348647,
"name": "Motorcycles",
"pid": 0,
"children": [
{
"id": 1573695355619,
"name": "Ducatti",
"pid": 1573695348647
}
]
}
]
Suppose I have this node-tree-like array in PHP (represented above in json for readability). For a given child node ID, I would like to find all parent node IDs that it's nested under. For example,
getParentNodes($haystack, $child_node_id=1573695328137); //[1573695284631, 1573695292010, 1573695305619]
I assume this is a use case for recursion. Here's my best attempt:
function getParentNodes($haystack, $child_node_id) {
if( empty($haystack->children) )
return;
foreach($haystack->children as $child) {
if($child->id == $child_node_id) {
// $child found, now recursively get parents
} else {
getParentNodes($child, $child_node_id);
}
}
}
This one will walk the tree until it hits the desired id.
In all cases where the leaf is not the desired one, it will return false - and collapse up the stack resulting in false or an array of parent-ids if the child is found.
Code
function getParentNodes($haystack, $child_node_id) {
foreach ($haystack as $element) {
if ($element['id'] === $child_node_id) {
// return [$element['id']]; // uncomment if you want to include child itself
return [];
} else if (array_key_exists('children', $element)) {
$parentNodes = getParentNodes($element['children'], $child_node_id);
if ($parentNodes !== false) {
return [$element['id'], ...$parentNodes];
}
}
}
return false;
}
Outputs parent ids:
array(2) {
[0]=>
int(1573695284631)
[1]=>
int(1573695305619)
}
Working example.
You missing return result. This is what you want.
function getParentNodes($arr, $child_node_id) {
$result = [];
foreach($arr as $item) {
if($item->pid == $child_node_id) {
$result[] = $item->id;
}
if(!empty($item->children)) {
$result[] = getParentNodes($item->children, $child_node_id);
}
}
return $result;
}
also you need get values as flat array
$values = getParentNodes($values, 1573695284631);
// do flat arr
array_walk_recursive($values,function($v) use (&$result){ $result[] = $v; });
// your values
var_dump($result);
Source reference for flat array
I ended up writing 2 recursive functions
function treeSearch($needle, $haystack) {
foreach($haystack as $node) {
if($node->id == $needle) {
return $node;
} elseif ( isset($node->children) ) {
$result = treeSearch($needle, $node->children);
if ($result !== false){
return $result;
}
}
}
return false;
}
treeSearch will find the node in the tree, then I need to recursively go up the tree until the parent id (pid) is 0
function getParents($node, $hierarchy, $all_parent_ids=[]) {
if($node->pid != 0) {
$parent_node = treeSearch($node->pid, $hierarchy);
$all_parent_ids[] = $parent_node->id;
$result = getParents($parent_node, $hierarchy, $all_parent_ids);
if ($result !== false){
return $result;
}
}
return $all_parent_ids;
}
then, supposing the tree is called $tree I can call them like:
$node = treeSearch(1573695328137, $tree);
$parents = getParents($node, $tree);
This is the best solution to take the parent of a child !
function getPathParent($id, $tree='',$opts='', &$path = array()) {
$in = array_replace(array(
'id'=>'id',
'child'=>'children',
'return'=>'id'
),(array)$opts);
if ( is_array($tree) && !empty($tree) ){
foreach ($tree as $item) {
if ($item[$in['id']] == $id) {
array_push($path, $item[$in['return']]);
return $path;
}
if ( isset($item[$in['child']]) && !empty($item[$in['child']]) ) {
array_push($path, $item[$in['return']]);
if (getPathParent($id, $item[$in['child']],$opts, $path) === false) {
array_pop($path);
} else {
return $path;
}
}
}
}
return false;
}
$tree = [
[
"id" => 1573695284631,
"name" => "Cars",
"pid" => 0,
"children" => [
[
"id" => 1573695292010,
"name" => "Audi",
"pid" => 1573695284631
],
[
"id" => 1573695305619,
"name" => "BMW",
"pid" => 1573695284631,
"children" => [
[
"id" => 1573695328137,
"name" => "3 Series",
"pid" => 1573695305619
],
[
"id" => 1573695335102,
"name" => "X5",
"pid" => 1573695305619
]
]
]
]
],
[
"id" => 1573695348647,
"name" => "Motorcycles",
"pid" => 0,
"children" => [
[
"id" => 1573695355619,
"name" => "Ducatti",
"pid" => 1573695348647
]
]
]
];
$getParentNode = getPathParent(1573695335102,$tree);
var_export($getParentNode);
// return:
/*
array (
0 => 1573695284631,
1 => 1573695305619,
2 => 1573695335102,
)
*/
$getParentNode = getPathParent(1573695335102,$tree,array('return'=>'name'));
var_export($getParentNode);
// return:
/*
array (
0 => 'Cars',
1 => 'BMW',
2 => 'X5',
)
*/
$getParentNode = getPathParent(1573695335102,$tree,array('id'=>'id','child'=>'children','return'=>'pid'));
var_export($getParentNode);
// return:
/*
array (
0 => 0,
1 => 1573695284631,
2 => 1573695305619,
)
*/
I have given the array:
array(
"firstName": null,
"lastName": null,
"category": [
"name": null,
"service": [
"foo" => [
"bar" => null
]
]
]
)
that needs to be transform into this:
array(
0 => "firstName",
1 => "lastName",
2 => "category",
"category" => [
0 => "name",
1 => "service",
"service" => [
0 => "foo",
"foo" => [
0 => "bar"
]
]
]
)
The loop should check if a value is an array and if so, it should add the key as a value (0 => category) to the root of array and then leave the key as it is (category => ...) and traverse the value again to build the tree as in example.
I am stuck with this and every time I try, I get wrong results. Is there someone who is array guru and knows how to simply do it?
The code so far:
private $array = [];
private function prepareFields(array $fields):array
{
foreach($fields as $key => $value)
{
if(is_array($value))
{
$this->array[] = $key;
$this->array[$key] = $this->prepareFields($value);
}
else
{
$this->array[] = $key;
}
}
return $this->array;
}
You could make use of array_reduce:
function prepareFields(array $array): array
{
return array_reduce(array_keys($array), function ($result, $key) use ($array) {
$result[] = $key;
if (is_array($array[$key])) {
$result[$key] = prepareFields($array[$key]);
}
return $result;
});
}
Demo: https://3v4l.org/3BfKD
You can do it with this, check the Demo
function array_format(&$array){
$temp_array = [];
foreach($array as $k=>$v){
$temp_array[] = $k;
if(is_array($v)){
array_format($v);
$temp_array[$k] = $v;
}
}
$array = $temp_array;
}
array_format($array);
print_r($array);
I have two tables order and orderDetail. i have multiple delivery address in order detail table based on id of order table
i want to display id from order table and deliveryAddress from order detail table.i am getting below output when i print..
but unable to display delivery_address.please anyone can suggest how i display delivery_address..
{
"responseData": {
"status": 1,
"message": "",
"result": [
{
"Order": {
"id": "677",
"detail_location_instructions": "Near Inox"
},
"OrderDetail": [
{
"order_id": "677",
"delivery_address": "Smart Club Gimnasio - Avenida Álvarez Thomas, Buenos Aires, Autonomous City of Buenos Aires, Argentina"
},
{
"order_id": "677",
"delivery_address": "Lower Fort Street, Dawes Point, New South Wales, Australia"
}
]
},
{
"Order": {
"id": "680"
},
"OrderDetail": []
},
{
"Order": {
"id": "684"
},
"OrderDetail": [
{
"order_id": "684",
"delivery_address": "Four Seasons - Posadas"
}
]
}
]
}
}
below is my code
public function getOrderlist(){
if($this->processRequest){
$err = false;
if(empty($this->requestData['id'])){
$this->responceData['message'] = "Please provide User ID";
$err = true;
}
if(!$err){
$id = trim($this->requestData['id']);
$conditions = array('Order.user_id'=>$id);
$data = $this->Order->find('all',array('conditions'=>$conditions));
if(!empty($data)){
$c = array();
foreach ($data as $key => $value) {
$c[] = array(
'Id' => $value['Order']['id'],
'deliveryAddress' => $value['OrderDetail']['delivery_address']
);
}
}
$this->responceData['result'] = $c;
$this->responceData['status'] = 1;
}
}
}
You have to put the deliveryAddress in array
$c = array();
foreach ($data as $key => $value) {
$myOrders = [
'Id'=>$value['Order']['id'],
'deliveryAddress'=>[]
];
foreach($value['OrderDetail'] as $address){
$myOrders['deliveryAddress'][] = $address['delivery_address'];
}
$c[] = $myOrders;
}
Hope this will help
can you trying below code.
foreach ($data as $key => $value) {
$c[] = array(
'Order' => array(
'id'=>$value['Order']['id'],
'detail_location_instructions' => $value['Order']['detail_location_instructions'],
),
'OrderDetail' => array(
'order_id'=>$value['Order']['id'],
'deliveryAddress' => $value['OrderDetail']['delivery_address'],
),
)
}
There is cases where you dont get the delivery address, in that case, you need to check if it exists first. use the Hash utility for that purpose.
I transformed the data to an array, in order for the class Hash to work.
public function getOrderlist(){
if($this->processRequest){
$err = false;
if(empty($this->requestData['id'])){
$this->responceData['message'] = "Please provide User ID";
$err = true;
}
if(!$err){
$id = trim($this->requestData['id']);
$conditions = array('Order.user_id'=>$id);
$data =(array) $this->Order->find('all',array('conditions'=>$conditions));
if(!empty($data)){
$c = array();
foreach ($data as $key => $value) {
$c[] = array(
'Id' => Hash::get($value, 'Order.id'),
'deliveryAddress' => current(Hash::extract($value, 'OrderDetail.{n}.delivery_address', array()))
);
}
}
$this->responceData['result'] = $c;
$this->responceData['status'] = 1;
}
}
}
I am trying to write a recursive function that will iterate over an array of arrays and sum a specific field. Here is an example of an array:
{
"68": {
"10": [
{
"id": "3333",
"sumTHis": "5"
}
]
},
"69": {
"45": [
{
"id": "3333",
"sumTHis": "5"
}
],
"50": [
{
"id": "3330",
"sumTHis": "5"
},
{
"id": "3331",
"sumTHis": "5"
},
{
"id": "3332",
"sumTHis": "5"
},
{
"id": "3333",
"sumTHis": "5"
}
]
}
}
The problem is that the array could be any number of sub-arrays deep. In the end, I would like to be able to sum all "sumTHis" nodes throughout the entire array The code I have so far is this:
//in body
$sumThis= recurse_get_total($array, 'sumTHis');
//recursive function
function recurse_get_total($report_data, $valId, $total = 0){
try{
foreach ($report_data as $key => $value) {
if(is_array_of_arrays($value)){
recurse_get_total($value, $valId, $total);
}else{
$total = $total + $value[$valId];
return $total;
}
}
return $total;
}catch(Exception $err){
throw $err;
}
}
function is_array_of_arrays($isArray){
try{
if(is_array($isArray)){
foreach($isArray as $key => $value){
if(!is_array($value)){
return false;
}
}
return true;
}
}catch(Exception $err){
throw $err;
}
}
This function starts to iterate over the array but gets kicked out after the first one and returns 0. Can anyone help out?
Thanks
jason
Going about this problem I set something up with "array_walk_recursive". Seeing that you want to add some stuff independent of the depth of the arrays, this seems to work.
It is not solving it with what you have, but perhaps this different approach will get you there.
$sum = 0;
$array = array(
"one" => array(
"day" => "tuesday",
"week" => "20",
"findthis" => 10
),
"two" => array("subone" => array(
"some" => "one",
"findthis" => 23
)),
"deeperthree" => array("subtwo" => array("deeper" => array(
"one" => "entry",
"findthis" => 44
)))
);
function callback($val, $key, $arg) {
if ($key == "findthis") {
$arg[0]($val, $arg[1]);
}
};
$function = function($num, &$sum) {
$sum = $sum + $num;
echo $sum . " ";
};
array_walk_recursive($array, "callback", array( $function, &$sum ));
result: 10 33 77