How to Create recursive array from recursive array? - php

Here is input array with an n-level depth
array
(
[0] => array
(
[id] => 1
[parent_id] => 0
[variable_name] => menus
[variable_value] =>
[children] => array
(
[0] => array
(
[id] => 2
[parent_id] => 1
[variable_name] => products
[variable_value] => {"name":"Products", "link":"cctv.html", "show":"1"},
)
[1] => array
(
[id] => 3
[parent_id] => 1
[variable_name] => companies
[variable_value] => {"name":"Companies", "link":"companies.html", "show":"1"},
),
),
)
[1] => array
(
[id] => 4
[parent_id] => 0
[variable_name] => breadcrumbs
[variable_value] =>
[children] => array
(
[0] => array
(
[id] => 5
[parent_id] => 4,
)
[1] => array
(
[id] => 6
[parent_id] => 4
[variable_name] => companies
[variable_value] => {"name":"Companies", "link":"companies.html", "show":"1"},
),
),
)
[2] => array
(
[id] => 7
[parent_id] => 0
[variable_name] => products
[variable_value] =>
[children] => array
(
[0] => array
(
[id] => 8
[parent_id] => 7
[variable_name] => pages
[variable_value] =>
[children] => array
(
[0] => array
(
[id] => 9
[parent_id] => 8
[variable_name] => child_category_page
[variable_value] =>
[children] => array
(
[0] => array
(
[id] => 10
[parent_id] => 9
[variable_name] => middle
[variable_value] =>
[children] => array
(
[0] => array
(
[id] => 11
[parent_id] => 10
[variable_name] => left
[variable_value] => {"name":"Companies", "link":"companies.html", "show":"1", "test":1},
),
),
),
),
),
),
),
),
),
)
I want to convert it into,
[
'menus' => [
'products' => [
'name' => 'Products',
'link' => 'cctv.html',
'show' => true,
],
'companies' => [
'name' => 'Companies',
'link' => 'companies.html',
'show' => true,
],
],
'breadcrumbs' => [
'news' => [
'text' => 'News',
'show' => true,
'link' => 'news.html',
],
'companies' => [
'text' => 'Companies',
'show' => true,
'link' => 'companies.html',
],
],
'products' => [
'pages' => [
'child_category_page' => [
'middle' => [
'left' => [
'text' => 'Companies',
'show' => true,
'link' => 'companies.html',
],
],
],
],
],
];
What I have tried is,
$data = DB::table("SITE_CONFIGS")->where("parent_id", 0)->get();
$data = get_tree_site_configs($data);
function get_tree_site_configs($data, $parent=0, &$result=[]){
$data = json_decode(json_encode($data),true);
$branch = [];
foreach ($data as $key => &$value) {
if($parent == $value['parent_id']){
$has_sub = DB::table("SITE_CONFIGS")->where("parent_id", $value['id'])->get();
$children = get_tree_site_configs($has_sub, $value['id'],$result);
if($children){
$value['children'] = $children;
}
// pr($value);
$branch[] = $value;
}
}
return $branch;
}
Note: There is parent-child relation to n-level, parent id with variable_value are leaf notes, means they don't have any children, rest all are parents of some records.

function get_tree_site_configs(array $config) {
$result = [];
foreach ($config as $item) {
if (isset($item['children'])) {
$value = get_tree_site_configs($item['children']);
} else {
$value = $item['variable_value'];
}
$result[$item['variable_name']] = $value;
}
return $result;
}

Related

how to get a slice of a multidimensional array using an array with index keys

I have an array
$arr = [
[
'id' => 10,
'name' => 'John',
'occupation' => 'engineer',
'points' => 10
],
[
'id' => 10,
'name' => 'John',
'occupation' => 'librarian',
'points' => 14
],
[
'id' => 7,
'name' => 'Sarah',
'occupation' => 'artist',
'points' => 21
],
[
'id' => 7,
'name' => 'Sarah',
'occupation' => 'teacher',
'points' => 17
],
[
'id' => 10,
'name' => 'John',
'occupation' => 'butcher',
'points' => 7
],
[
'id' => 7,
'name' => 'Sarah',
'occupation' => 'engineer',
'points' => 9
],
[
'id' => 25,
'name' => 'Andreea',
'occupation' => 'judge',
'points' => 11
]
];
And I use this built in functions to get unique ids:
$people = array_column($arr, 'id', 'id');
And then I use a foreach to get every occurrence of each user in the main array $arr:
foreach($people as $id){
$keys = array_keys(array_column($arr, 'id'), $id);
}
This is the return:
Array
(
[0] => 0
[1] => 1
[2] => 4
)
Array
(
[0] => 2
[1] => 3
[2] => 5
)
Array
(
[0] => 6
)
Now in order to build a small array for each person I could loop trough this small arrays that contain the keys from the main array and get the values and ending up with small slices.
But, how can I get the actual $arr values for each person instead of getting just the keys? (using as little resources as possible)
I need the result to be like this:
Array
(
[10] => Array
(
[0] => Array
(
[id] => 10
[name] => John
[occupation] => engineer
[points] => 10
)
[1] => Array
(
[id] => 10
[name] => John
[occupation] => librarian
[points] => 14
)
[2] => Array
(
[id] => 10
[name] => John
[occupation] => butcher
[points] => 7
)
)
[7] => Array
(
[0] => Array
(
[id] => 7
[name] => Sarah
[occupation] => artist
[points] => 21
)
[1] => Array
(
[id] => 7
[name] => Sarah
[occupation] => teacher
[points] => 17
)
[2] => Array
(
[id] => 7
[name] => Sarah
[occupation] => engineer
[points] => 9
)
)
[25] => Array
(
[0] => Array
(
[id] => 25
[name] => Andreea
[occupation] => judge
[points] => 11
)
)
)
P.S: I don't need to keep the key index the same.
You can do it in a more efficient way,Demo
$result = [];
foreach($arr as $v){
$result[$v["id"]][] = $v;
}
print_r($result);
use a function of group by like:
$byGroup = group_by("id", $arr);
function group_by($key, $data) {
$result = array();
foreach($array as $val) {
if(array_key_exists($key, $val)){
$result[$val[$key]][] = $val;
}else{
$result[""][] = $val;
}
}
return $result;
}

Php merge two elements of an array based on some common value and add other values

I have a below array:
[product] => Array
(
[0] => Array
(
[qty] => 1
[code] => 147818
[price] => 11
[name] => Product1
)
[1] => Array
(
[qty] => 2
[code] => 147818
[price] => 11
[name] => Product1
)
[2] => Array
(
[qty] => 1
[code] => 567432
[price] => 31
[name] => Product2
)
)
I want to add quantities if the code is same. That is, I want the resulting array to be:
[product] => Array
(
[0] => Array
(
[qty] => 3
[code] => 147818
[price] => 11
[name] => Product1
)
[1] => Array
(
[qty] => 1
[code] => 567432
[price] => 31
[name] => Product2
)
)
It should merge the elements only if the code is same. How can I achieve this?
Try this code, it merge and sum the qty by code
$products = [
[
'qty' => 1,
'code' => 147818,
'price' => 11,
'name' => 'Product1'
],
[
'qty' => 2,
'code' => 147818,
'price' => 11,
'name' => 'Product1'
],
[
'qty' => 1,
'code' => 567432,
'price' => 31,
'name' => 'Product2'
],
];
$output = [];
for ($i=0; $i<count($products); $i++) {
if ($output[$products[$i]['code']]['code'] == $products[$i]['code']) {
$output[$products[$i]['code']]['qty'] += $products[$i]['qty'];
}else{
$output[$products[$i]['code']] = $products[$i];
}
}
$output = array_values($output);
print_r($output);

PHP flat array to multi-dimensional array by parent keys?

How can I turn this flat array into a multi-dimensional array according to the matched key?
$items = [
0 => [
'id' => 100,
'parent' => 0,
'url' => 'Home'
],
1 => [
'id' => 101,
'parent' => 0,
'url' => 'About'
],
2 => [
'id' => 102,
'parent' => 101,
'url' => 'Group'
],
3 => [
'id' => 103,
'parent' => 102,
'url' => 'Mission'
],
4 => [
'id' => 104,
'parent' => 102,
'url' => 'Vision'
],
];
My attempt:
$new_items = array();
foreach ($items as $key => $item) {
// Store what you need.
$temp_item = array(
'id' => $item['id'],
'url' => $item['url'],
'parent_id' => $item['parent'],
'children' => array()
);
// Item does not have a parent so item_parent equals 0 (false).
if (!$item['parent']) {
// Push the item to the array.
array_push($new_items, $temp_item);
}
// Item that has a parent.
if ($item['parent']) {
// Search key by column 'id'.
$key = array_search($item['parent'], array_column($new_items, 'id'));
// Push sub item to the children array.
array_push($new_items[$key]['children'], $temp_item);
}
}
print_r($new_items);
Result:
Array
(
[0] => Array
(
[id] => 100
[url] => Home
[parent_id] => 0
[children] => Array
(
[0] => Array
(
[id] => 103
[url] => Mission
[parent_id] => 102
[children] => Array
(
)
)
[1] => Array
(
[id] => 104
[url] => Vision
[parent_id] => 102
[children] => Array
(
)
)
)
)
[1] => Array
(
[id] => 101
[url] => About
[parent_id] => 0
[children] => Array
(
[0] => Array
(
[id] => 102
[url] => Group
[parent_id] => 101
[children] => Array
(
)
)
)
)
)
This is what I am after:
Array
(
[0] => Array
(
[id] => 100
[url] => Home
[parent_id] => 0
[children] => Array
(
)
)
[1] => Array
(
[id] => 101
[url] => About
[parent_id] => 0
[children] => Array
(
[0] => Array
(
[id] => 102
[url] => Group
[parent_id] => 101
[children] => Array
(
[0] => Array
(
[id] => 103
[url] => Mission
[parent_id] => 102
[children] => Array
(
)
)
[1] => Array
(
[id] => 104
[url] => Vision
[parent_id] => 102
[children] => Array
(
)
)
)
)
)
)
)
Any ideas and suggestions?
From link
I have changed function parameters as per requirement.
Here is your code.
function buildTree(array $elements, $options = [
'parent_id_column_name' => 'parent',
'children_key_name' => 'children',
'id_column_name' => 'id'], $parentId = 0)
{
$branch = array();
foreach ($elements as $element) {
if ($element[$options['parent_id_column_name']] == $parentId) {
$children = buildTree($elements, $options, $element[$options['id_column_name']]);
if ($children) {
$element[$options['children_key_name']] = $children;
}else{
$element[$options['children_key_name']] = []; // added this line for empty children array
}
$branch[] = $element;
}
}
return $branch;
}
Here is your working demo.

Building new multidimensional array from multidimensional array and interpreting the order

I have been trying to get this to work for 7.5 hours now, but my brain has melted.
I have a multi-dimensional array similar to the following:
array (
'expanded' => true,
'key' => 'root_1',
'title' => 'root',
'children' =>
array (
0 =>
array (
'folder' => false,
'key' => '_1',
'title' => 'News',
'data' =>
array (
'id' => '3',
'parent_id' => 0,
),
),
1 =>
array (
'folder' => true,
'key' => '_2',
'title' => 'Animations',
'data' =>
array (
'id' => '5',
'parent_id' => '0',
),
'children' =>
array (
0 =>
array (
'folder' => false,
'key' => '_3',
'title' => 'The Simpsons',
'data' =>
array (
'id' => '1',
'parent_id' => '5',
),
),
1 =>
array (
'folder' => false,
'key' => '_4',
'title' => 'Futurama',
'data' =>
array (
'id' => '4',
'parent_id' => '5',
),
),
),
),
2 =>
array (
'folder' => true,
'key' => '_5',
'title' => 'Episodes',
'data' =>
array (
'id' => '6',
'parent_id' => '0',
),
'children' =>
array (
0 =>
array (
'folder' => true,
'key' => '_6',
'title' => 'UK Episodes',
'data' =>
array (
'id' => '7',
'parent_id' => '6',
),
'children' =>
array (
0 =>
array (
'folder' => false,
'key' => '_7',
'title' => 'Coupling',
'data' =>
array (
'id' => '2',
'parent_id' => '7',
),
),
),
),
1 =>
array (
'folder' => true,
'key' => '_8',
'title' => 'AU Episodes',
'data' =>
array (
'id' => '8',
'parent_id' => '6',
),
),
),
),
),
)
I need to search through all sub arrays and build a new array returning the id and parent_id of each of the children AND also interpreting the order of the array children from the order they appear in the original array.
The output needs to end up something like this:
Array
(
[0] => Array
(
[id] => 1
[parent_id] => 5
[order] => 1
)
[1] => Array
(
[id] => 2
[parent_id] => 7
[order] => 1
)
[2] => Array
(
[id] => 4
[parent_id] => 5
[order] => 2
)
)
I have tried the following recursion approach, however my code turns into a mess, and thats before I've even attempted to set the order of the items.
I've also searched stackoverflow for another example that I could learn from however I haven't found anything yet... If there is another example please feel free to point me in the right direction.
I appreciate any assistance!
A super easy way to run over all these is to use a RecursiveIteratorIterator over a RecursiveArrayIterator, pluck out the 'data' arrays and add in the key as the order.
Example:
$array = []; // Your starting array with stuff in it.
$iterator = new RecursiveIteratorIterator(
new RecursiveArrayIterator($array),
RecursiveIteratorIterator::SELF_FIRST
);
$result = [];
foreach ($iterator as $key => $value) {
if (isset($value['data'])) {
$result[] = array_merge($value['data'], ['order' => $key]);
}
}
print_r($result);
Output:
Array
(
[0] => Array
(
[id] => 3
[parent_id] => 0
[order] => 0
)
[1] => Array
(
[id] => 5
[parent_id] => 0
[order] => 1
)
[2] => Array
(
[id] => 1
[parent_id] => 5
[order] => 0
)
[3] => Array
(
[id] => 4
[parent_id] => 5
[order] => 1
)
[4] => Array
(
[id] => 6
[parent_id] => 0
[order] => 2
)
[5] => Array
(
[id] => 7
[parent_id] => 6
[order] => 0
)
[6] => Array
(
[id] => 2
[parent_id] => 7
[order] => 0
)
[7] => Array
(
[id] => 8
[parent_id] => 6
[order] => 1
)
)
If i'm understanding what you're trying to do properly the below snippet should work. No need for the order key in each sub array because that's recorded automatically when you insert a new array index into $new_array.
Let me know if you have any other problems.
$new_array = [];
$current_array = []; //with all your data
foreach($current_array['children'] as $array) {
$new_array[] = [
'id' => $array['data']['id'],
'parent_id' => $array['data']['parent_id'];
];
}

PHP tree array remove levels

I have an "tree" array like the following. This is a navigation. Now i want to remove all levels >= 3. So i only want to get an array with the first two levels. Is there a way to trim/shorten the array like that.
Do you have a hint for me what i can look for?
Array
(
[0] => Array
(
[name] => Home
[level] => 1
[sub] =>
)
[1] => Array
(
[name] => Products
[level] => 1
[sub] => Array
(
[56] => Array
(
[name] => Product 1
[level] => 2
[sub] => Array
(
[61] => Array
(
[name] => Product 1b
[target] =>
[level] => 3
[sub] =>
)
)
)
[57] => Array
(
[name] => Product 2
[level] => 2
[sub] =>
)
)
)
[2] => Array
(
[name] => Contact
[level] => 1
[sub] =>
)
[3] => Array
(
[name] => Something Else
[level] => 1
[sub] =>
)
)
$data = [
0 => ['name' => 'Home', 'level' => 1, 'sub' => []],
1 => [
'name' => 'Products',
'level' => 2,
'sub' => [
'56' => [
'name' => 'Product 1',
'level' => 2,
'sub' => [
'61' => [ 'name' => 'Product 1b', 'target' => '', 'level' => 3, 'sub' => ''],
],
],
'57' => ['name' => 'Product 2', 'level' => 2, 'sub' => '']
]
],
2 => ['name' => 'Contact', 'level' => 1, 'sub' => []],
3 => ['name' => 'Something Else', 'level' => 1, 'sub' => []]
];
function processArray(&$arr) {
foreach ($arr as $key => $array) {
if ($array['level'] >= 3) {
unset($arr[$key]);
}
if (!empty($arr[$key]['sub'])) {
processArray($arr[$key]['sub']);
}
}
}
processArray($data);

Categories