How to fix recursion in php? - php

I try to iterate all parents/child in recursion:
foreach ($data as $k => $item) {
$data[$k]["children"] = $this->getChildren($all, $item);
}
And recursive function:
private function getChildren($list, $item)
{
$children = [];
if (is_array($item["children"])) {
foreach ($item["children"] as $k => $id) {
$children[] = $list[$id];
}
} else {
if (isset($list[$item["children"]])) {
$children[] = $list[$item["children"]];
}
}
return $children;
}
Problem is that I need to call getChildren inside getChildren for founded element $list[$id] to check if this element does contain array children.
I tried to call this:
$children[] = $this->getChildren($list, $list[$id]);
But it does not work.
I tried this way:
private function getChildren($list, $item)
{
$children = [];
if (is_array($item["children"]) && count($item["children"]) > 0) {
foreach ($item["children"] as $k => $id) {
return $this->getChildren($list, $list[$id]);
}
}
return $list[$id];
}
The array $all that I try to iterate by children:
array:12 [
"592d0b3bb3569e257208db81" => array:10 [
"_id" => MongoId {#266
+$id: "592d0b3bb3569e257208db81"
}
"name" => "Характеристики героя"
"default" => "data"
"visibility" => null
"type" => "2"
"value" => "data"
"prefix" => "data"
"type_value" => "object"
"children" => array:7 [
0 => "592d094eb3569eb07208db7e"
1 => "592d0961b3569ee17708db80"
2 => "592d0978b3569eb07108db7e"
3 => "592d0987b3569ead7108db91"
4 => "592d09a5b3569eae7108db81"
5 => "592d09c1b3569eae7208db82"
6 => "592d0ac3b3569eae7208db83"
]
"available" => "1"
]
"592d0ac3b3569eae7208db83" => array:10 [
"_id" => MongoId {#267
+$id: "592d0ac3b3569eae7208db83"
}
"name" => "Умения"
"default" => "skills"
"visibility" => null
"type" => "2"
"value" => "skills"
"prefix" => "skills"
"type_value" => "object"
"children" => array:4 [
0 => "592d094eb3569eb07208db7e"
1 => "592d0a1db3569ee17708db81"
2 => "592d0a2fb3569e257208db80"
3 => "592d0a58b3569ead7108db92"
]
"available" => "1"
]
"592d0a58b3569ead7108db92" => array:10 [
"_id" => MongoId {#268
+$id: "592d0a58b3569ead7108db92"
}
"name" => "Начальная прокачка"
"default" => "0"
"visibility" => null
"type" => "1"
"value" => "0"
"prefix" => "startPumping"
"type_value" => "integer"
"children" => []
"available" => "1"
]
"592d0a2fb3569e257208db80" => array:10 [
"_id" => MongoId {#269
+$id: "592d0a2fb3569e257208db80"
}
"name" => "Максимальная прокачка"
"default" => "0"
"visibility" => null
"type" => "1"
"value" => "0"
"prefix" => "maxPumping"
"type_value" => "integer"
"children" => []
"available" => "1"
]
"592d0a1db3569ee17708db81" => array:10 [
"_id" => MongoId {#270
+$id: "592d0a1db3569ee17708db81"
}
"name" => "Текущая прокачка"
"default" => "0"
"visibility" => null
"type" => "1"
"value" => "0"
"prefix" => "pumping"
"type_value" => "integer"
"children" => []
"available" => "1"
]
"592d09c1b3569eae7208db82" => array:10 [
"_id" => MongoId {#271
+$id: "592d09c1b3569eae7208db82"
}
"name" => "Свободных умений"
"default" => "0"
"visibility" => null
"type" => "1"
"value" => "0"
"prefix" => "freePumpingPoints"
"type_value" => "integer"
"children" => []
"available" => "1"
]
"592d09a5b3569eae7108db81" => array:10 [
"_id" => MongoId {#272
+$id: "592d09a5b3569eae7108db81"
}
"name" => "Требования"
"default" => "Что бы получить Этого персонажа, вам нужно заплатить миллион американских рублей и подарить нам почку"
"visibility" => null
"type" => "1"
"value" => "Что бы получить Этого персонажа, вам нужно заплатить миллион американских рублей и подарить нам почку"
"prefix" => "requirements"
"type_value" => "string"
"children" => []
"available" => "1"
]
"592d0987b3569ead7108db91" => array:10 [
"_id" => MongoId {#273
+$id: "592d0987b3569ead7108db91"
}
"name" => "Описание"
"default" => "Описание"
"visibility" => null
"type" => "1"
"value" => "Описание"
"prefix" => "description"
"type_value" => "string"
"children" => []
"available" => "1"
]
"592d0978b3569eb07108db7e" => array:10 [
"_id" => MongoId {#274
+$id: "592d0978b3569eb07108db7e"
}
"name" => "Название"
"default" => "Название"
"visibility" => null
"type" => "1"
"value" => "Название"
"prefix" => "name"
"type_value" => "string"
"children" => []
"available" => "1"
]
"592d0961b3569ee17708db80" => array:10 [
"_id" => MongoId {#275
+$id: "592d0961b3569ee17708db80"
}
"name" => "Уровень"
"default" => "0"
"visibility" => null
"type" => "1"
"value" => "0"
"prefix" => "level"
"type_value" => "integer"
"children" => []
"available" => "1"
]
"592d094eb3569eb07208db7e" => array:10 [
"_id" => MongoId {#276
+$id: "592d094eb3569eb07208db7e"
}
"name" => "Идентификатор"
"default" => "0"
"visibility" => null
"type" => "1"
"value" => "0"
"prefix" => "id"
"type_value" => "integer"
"children" => []
"available" => "1"
]
"592d0932b3569e277208db87" => array:10 [
"_id" => MongoId {#277
+$id: "592d0932b3569e277208db87"
}
"name" => "Сила отбития"
"default" => "0"
"visibility" => null
"type" => "1"
"value" => "0"
"prefix" => "hitForce"
"type_value" => "integer"
"children" => []
"available" => "1"
]
]"available" => "1"
]
]
My version of recursie:
private function getChildren($list, $item, $c)
{
if (is_array($item["children"])) {
foreach ($item["children"] as $k => $id) {
if(count($list[$id]["children"]) > 0){
$_id = (string)$list[$id]["_id"];
$c[][$_id] = $list[$id];
$c[][$_id]["children"] = $this->getChildren($list, $list[$id], $c);
} else {
$c[] = $list[$id];
}
}
}
return $c;
}
Calling:
foreach ($data as $k => $item) {
$data[$k]["children"] = $this->getChildren($all, $item, $c);
}

this is a quick example using a sampler array rather than your array, just to clarify and simplify the solution in a general context.
$data = [
0 => ['name' => 'b0', 'children' => [3,5]],
1 => ['name' => 'b1', 'children' => []],
2 => ['name' => 'b2', 'children' => [1]],
3 => ['name' => 'b3', 'children' => []],
4 => ['name' => 'b4', 'children' => []],
5 => ['name' => 'b5', 'children' => [4]],
];
function recursive($data, $childs)
{
$list = [];
foreach ($childs as $child) {
if (is_array($data[$child]['children'])) {
// storing the output of the recursive array in a tmp variable
$tmpArray['name'] = $data[$child]['name'];
$tmpArray['children'] = recursive($data, $data[$child]['children']);
} else {
$tmpArray = $data[$child];
}
$list[] = $tmpArray;
}
return $list;
}
foreach ($data as $key => $value) {
// Here we are going to check whether the array have inner childs or not , only to take in account the other empty elements
if (is_array($value['children']) && count($value['children']) > 0) {
$list[] = recursive($data, $value['children']);
} else {
$list[] = $value;
}
}
print_r($list);
here is a quick demo : https://eval.in/807433
P.S, the more data you will get, the more load & time you will get
maybe redesign your mongoDB document will be a good choice to avoid this, maybe

Related

recursive function transform nested array

Im my laravel project I have this nested array that needs to be updated (transformed - for the frontend):
array:2 [
0 => array:3 [
"entity_id" => 931
"entity" => "user"
"children" => array:2 [
0 => array:2 [
"entity_id" => 5
"entity" => "location"
]
1 => array:2 [
"entity_id" => 932
"entity" => "user"
]
]
]
1 => array:2 [
"entity_id" => 486
"entity" => "user"
]
]
EXPECTED ARRAY:
array:2 [
0 => array:4 [
"id" => 931
"text" => "Test User 1"
"type" => "user"
"children" => array:2 [
0 => array:3 [
"id" => 5
"text" => "Location 1"
"type" => "location"
]
1 => array:3 [
"id" => 932
"text" => "Test User 2"
"type" => "user"
]
]
]
1 => array:3 [
"id" => 486
"text" => "Test User 3"
"type" => "user"
]
]
I have created a recursive function for this job
public function getNewStructure($tree, &$output) {
foreach($tree as $data) {
$output[] = array(
'id' => $data['entity_id'],
'text' => $data['user'] === 'user' ? User::find($data['entity_id'])->name : Location::find($data['entity_id'])->name,
'type' => $data['entity']
);
$this->getNewStructure($data['children'] ?? [], $output);
}
return $output;
}
but it not returns as expected:
array:4 [
0 => array:3 [
"id" => 931
"text" => "Test User 1"
"type" => "user"
]
0 => array:3 [
"id" => 5
"text" => "Location 1"
"type" => "location"
]
1 => array:3 [
"id" => 932
"text" => "Test User 2"
"type" => "user"
]
1 => array:3 [
"id" => 486
"text" => "Test User 3"
"type" => "user"
]
]
How can I add the children to the $output array in the recursive function ???
I have tried by adding the children key:
$this->getNewStructure($data['children'] ?? [], $output['children']);
as when iterating again it will push the current array in the right place.... but is not working...
I fixed
public function getNewStructure($tree, &$output) {
foreach($tree as $data) {
$element = array(
'id' => $data['entity_id'],
'text' => $data['user'] === 'user' ? User::find($data['entity_id'])->name : Location::find($data['entity_id'])->name,
'type' => $data['entity']
);
if(is_array($data['children']) && count($data['children']) > 0) {
$element['children'] = $this->getNewStructure($data['children'], $element['children']);
}
$output[] = $element;
}
return $output;
}

Php Recursivity: Convert a multidimensional associative array into an array that contains each level of data

I am looking for the best way to convert a multidimensional associative array into a new array, where each row is the concatenation of each column ex :
$datas[] = [
"id" => "1000",
"parent" => "0",
"level" => "1",
"children" => [
[
"id" => "1001",
"parent" => "1000",
"level" => "2",
"children" => [
[
"id" => "1002",
"parent" => "1001",
"level" => "3",
"children" => [
[
"id" => "1003",
"parent" => "1002",
"niveau" => "4",
],
[
"id" => "1004",
"parent" => "1002",
"niveau" => "4",
],
[
"id" => "1005",
"parent" => "1002",
"niveau" => "4",
]
]
],
[
]
]
],
[
"id" => "1006",
"parent" => "1000",
"level" => "2"
]
],
[
"id" => "1007",
"parent" => "0",
"level" => "1"
]
];
Here's my method :
public function recursData(array $datas, &$str ="", &$row =[], int $level = 0)
{
$level++;
foreach ($datas as $data) {
foreach($data as $key => $d) {
if (is_array($d)) {
$this->recursData($d, $str, $row,$level);
} else {
$str.= "{$level}_{$key}_{$d}|";
if ($key == "parent") {
$row[] = $str;
}
}
}
}
return $row;
}
Output (not what i'm looking for) :
array:8 [
0 => "1_id_1000|1_parent_0|"
1 => "1_id_1000|1_parent_0|2_id_1001|2_parent_1000|"
2 => "1_id_1000|1_parent_0|2_id_1001|2_parent_1000|3_id_1002|3_parent_1001|"
3 => "1_id_1000|1_parent_0|2_id_1001|2_parent_1000|3_id_1002|3_parent_1001|4_id_1003|4_parent_1002|"
4 => "1_id_1000|1_parent_0|2_id_1001|2_parent_1000|3_id_1002|3_parent_1001|4_id_1003|4_parent_1002|4_id_1004|4_parent_1002|"
5 => "1_id_1000|1_parent_0|2_id_1001|2_parent_1000|3_id_1002|3_parent_1001|4_id_1003|4_parent_1002|4_id_1004|4_parent_1002|4_id_1005|4_parent_1002|"
6 => "1_id_1000|1_parent_0|2_id_1001|2_parent_1000|3_id_1002|3_parent_1001|4_id_1003|4_parent_1002|4_id_1004|4_parent_1002|4_id_1005|4_parent_1002|2_id_1006|2_parent_1000|"
7 => "1_id_1000|1_parent_0|2_id_1001|2_parent_1000|3_id_1002|3_parent_1001|4_id_1003|4_parent_1002|4_id_1004|4_parent_1002|4_id_1005|4_parent_1002|2_id_1006|2_parent_1000|1_id_1007|1_parent_0|"
]
The output i'm looking for:
array:8 [
0 => "1_id_1000|1_parent_0"
1 => "1_id_1000|1_parent_0|2_id_1001|2_parent_1000"
2 => "1_id_1000|1_parent_0|2_id_1001|2_parent_1000|3_id_1002|3_parent_1001"
3 => "1_id_1000|1_parent_0|2_id_1001|2_parent_1000|3_id_1002|3_parent_1001|4_id_1003|3_parent_1002"
4 => "1_id_1000|1_parent_0|2_id_1001|2_parent_1000|3_id_1002|3_parent_1001|4_id_1004|3_parent_1002"
5 => "1_id_1000|1_parent_0|2_id_1001|2_parent_1000|3_id_1002|3_parent_1001|4_id_1005|3_parent_1002"
6 => "1_id_1000|1_parent_0|2_id_1006|2_parent_1000"
7 => "1_id_1007|1_parent_0"
]
I'm stuck to finish this properly, I tried lot of things, but can't understand what to do obtain what I want to resolve this. Hope someone could help :)

PHP - Add new object to every array of objects

Consider this array of objects in PHP:
array:2 [
0 => array:4 [
"Row_Id" => 256
"Start_Date" => "2020-05-16"
"account_code" => ""
"caller_number" => "452"
]
1 => array:4 [
"Row_Id" => 257
"Start_Date" => "2020-05-16"
"account_code" => ""
"caller_number" => "42"
]
2 => array:4 [
"Row_Id" => 258
"Start_Date" => "2020-05-16"
"account_code" => ""
"caller_number" => "428"
]
]
I want to add "callee_number:100" in every array so my output should look like these:
array:2 [
0 => array:5 [
"Row_Id" => 256
"Start_Date" => "2020-05-16"
"account_code" => ""
"caller_number" => "452"
"callee_number" => "100"
]
1 => array:5 [
"Row_Id" => 257
"Start_Date" => "2020-05-16"
"account_code" => ""
"caller_number" => "42"
"callee_number" => "100"
]
2 => array:5 [
"Row_Id" => 258
"Start_Date" => "2020-05-16"
"account_code" => ""
"caller_number" => "428"
"callee_number" => "100"
]
]
I have taken the above input array in $get variable. Now I am calling array_push to append callee_number to every array:
array_push($get,[
'callee_number':'100'
]);
Also tried using array_merge but callee_number is not getting appended. How can I achieve that ?
Given the following array:
$array = [
[
"Row_Id" => 256,
"Start_Date" => "2020-05-16",
"account_code" => "",
"caller_number" => "452",
],
[
"Row_Id" => 257,
"Start_Date" => "2020-05-16",
"account_code" => "",
"caller_number" => "42",
],
[
"Row_Id" => 258,
"Start_Date" => "2020-05-16",
"account_code" => "",
"caller_number" => "428",
],
];
Native PHP
$array = array_map(function ($item) { return $item + ['callee_number' => 100]; }, $array);
Using collections
$array = collect($array)->map(function ($item) { return $item + ['callee_number' => 100]; })->toArray();
Using PHP 7.4 shorthands
$array = array_map(fn($item) => $item + ['callee_number' => 100], $array);
// Or
$array = collect($array)->map(fn($item) => $item + ['callee_number' => 100])->toArray();
To add or modify an element in each sub-array you would do this:
foreach ($get as &$g) {
$g["callee_number"] = 100;
}
Or this:
for ($c = 0; $c < count($get); $c++) {
$get[$c]["callee_number"] = 100;
}

Check if the given value exist in another array?

I have an array with some values as below:
$array1 = [
0 => "year",
1 => "month"
];
I make a loop to this array and check if its value exist in following array.
array:3 [
0 => array:3 [
"name" => "year"
"mandatory" => true
"type" => "integer"
]
1 => array:3 [
"name" => "month"
"mandatory" => true
"type" => "integer"
]
2 => array:3 [
"name" => "id"
"mandatory" => false
"type" => "integer"
]
]
If if exists then I have to return array something like this
array[
"year" => [
"mandatory" => true
"type" => "integer"
],
"month" => [
"mandatory" => true
"type" => "integer"
],
]
This is the code so far I have tried.
$keys = array_keys($params);
$fields = $config["fields"];
$finalArr = array();
foreach($keys as $key) {
if(in_array($key, array_column($fields, "name"))) {
$finalArr[$key] = array();
}
$finalArr[$key][] = $fields;
}
But this returns all the records.
Can anybody help me.
Iterate over your $fields and check if field's name exists in $keys:
foreach ($fields as $field) {
if (in_array($field['name'], $keys)) {
$finalArr[$field['name']] = $field;
}
}

php how to grouping by id

I'm very new in PHP. I'm doing with the array data structure. Currently, I got two result which is the same ID but different details. I need to combine the details based on the ID.
This is my array result
array:2 [
0 => array:13 [
"id" => "1"
"date" => "01-02-2019"
"order" => array:1 [
0 => array:2 [
"code" => "F001"
"name" => "fish"
]
]
]
1 => array:13 [
"id" => "1"
"date" => "01-02-2019"
"order" => array:1 [
0 => array:2 [
"code" => "F002"
"name" => "chicken"
]
]
]
]
This is my expected result
array:1 [
0 => array:13 [
"id" => "1"
"date" => "01-02-2019"
"order" => array:2 [
0 => array:2 [
"code" => "F001"
"name" => "fish"
]
1 => array:2 [
"code" => "F002"
"name" => "chicken"
]
]
]
]
I'm trying to insert the order array if there have the same id
This is my code
public function order($value)
{
$group_id = [];
$groupItem = [];
foreach ($value as $item) {
$item['date'] = date('Y-m-d',strtotime($item['date']));
$groupItem = $item['order'][] = [
'id' => $item['id'],
'name' => $item['name'],
];
$group_id[$item['id']][]= $groupItem;
}
}
Result
array:1 [
"1" => array:1 [
0 => array:2 [
"code" => "F001"
"name" => "fish"
]
1 => array:2 [
"code" => "F002"
"name" => "chicken"
]
]
]
As you can see, I grouped the order but the date and id were missing.
Here is a working order function:
function order($input) {
$output = array();
foreach($input as $item) {
if (!isset($output[$item['id']])) {
$output[$item['id']] = array(
"id" => $item["id"],
"date" => $item["date"],
"order" => array()
);
}
$output[$item['id']]['order'][] = $item['order'];
}
return array_values($output);
}
INPUT:
array(
array(
"id" => "1",
"date" => "01-02-2019",
"order" => array(
array(
"code" => "F001",
"name" => "fish"
)
)
),
array(
"id" => "1",
"date" => "01-02-2019",
"order" => array(
array(
"code" => "F002",
"name" => "chicken"
)
)
)
);
OUTPUT:
array(
array(
"id"=> "1",
"date"=> "01-02-2019",
"order"=> array(
array(
array(
"code"=> "F001",
"name"=> "fish"
)
),
array(
array(
"code"=> "F002",
"name"=> "chicken"
)
)
)
)
)
Assign the proper data. Try -
foreach ($value as $item) {
$date = date('Y-m-d',strtotime($item['date']));
$id = $item['id'];
$group_id[$id]['id'] = $id;
$group_id[$id]['date'] = $date;
$group_id[$id]['order'][] = [
'id' => $item['id'],
'name' => $item['name'],
];
}
I would write something like this, if you need to account for multiple IDs:
$result = array_reduce( $input, function ( $result, $item ) {
$id = $item['id'];
if ( ! isset( $result[ $id ] ) ) { // We don't have an item yet.
$result[ $id ] = $item;
} else { // We have an item and need to add orders to it.
$result[ $id ]['order'] = array_merge( $result[ $id ]['order'], $item['order'] );
}
return $result;
}, [] );

Categories