Sort Multi-dimensional Array in PHP with multiple conditionals - php

I'm trying to build up a result array from a DB query and basicly I was wondering if the following would be possible
Array content:
Array
(
[0] => Array
(
[Section_Id] => 1
[Section_Name] => "Section1"
[Section_Parent] => NULL
[Section_Position] => 0
[Section_Depth] => 0
)
[1] => Array
(
[Section_Id] => 3
[Section_Name] => "Section2"
[Section_Parent] => NULL
[Section_Position] => 1
[Section_Depth] => 0
)
[2] => Array
(
[Section_Id] => 4
[Section_Name] => "SubSection1ForSection2"
[Section_Parent] => 3
[Section_Position] => 0
[Section_Depth] => 1
)
[3] => Array
(
[Section_Id] => 2
[Section_Name] => "SubSection1ForSection1"
[Section_Parent] => 1
[Section_Position] => 0
[Section_Depth] => 1
)
)
If you would Sort this one lets say on Section_Position it would return something like:
usort($sections, function($a, $b) {
return $a['section_position'] - $b['section_position'];
});
Section1
SubSection1ForSection2
SubSection1ForSection1
Section2
Whilst I need it to order the Sections with their respective childs:
Section1
SubSection1ForSection1
Section2
SubSection1ForSection2
I assume Somehow Duplicate Question is the way to think but I can't seem to find a way to make this work for me.
Is there a way to do this or do I have to make a workaround with forloop-gets so that I first get all the values for depth one and then using the name of the section to get all the values of depth two and so forth?
(Sorry for my english.)

Okay this might be an ugly solution but if you put everything in a function it look good :). The good thing is that it will work in your scenario.
Code:
$inputData = array(
array(
'Section_Id' => 1,
'Section_Name' => "Section1",
'Section_Parent' => NULL,
'Section_Position' => 1,
'Section_Depth' => 0,
),
array(
'Section_Id' => 2,
'Section_Name' => "Section2",
'Section_Parent' => NULL,
'Section_Position' => 0,
'Section_Depth' => 0
),
array(
'Section_Id' => 4,
'Section_Name' => "SubSection2ForSection2",
'Section_Parent' => 2,
'Section_Position' => 1,
'Section_Depth' => 1
),
array(
'Section_Id' => 5,
'Section_Name' => "SubSection1ForSection2",
'Section_Parent' => 2,
'Section_Position' => 0,
'Section_Depth' => 1
),
array(
'Section_Id' => 3,
'Section_Name' => "SubSection1ForSection1",
'Section_Parent' => 1,
'Section_Position' => 0,
'Section_Depth' => 1
)
);
$parentRecords = array();
$childRecords = array();
$sorted = array();
/* split in two collections */
foreach ($inputData as $sectionData) {
if (is_null($sectionData['Section_Parent'])) {
/* assume this is a parent */
$parentRecords[] = $sectionData;
} else {
/* assume we are on child row */
$childRecords[] = $sectionData;
}
}
/* now first order parents by Section_Position */
usort($parentRecords, function($a, $b) {
if ($a['Section_Position'] == $b['Section_Position']) {
return 0;
}
return $a['Section_Position'] > $b['Section_Position'] ? 1 : -1;
});
/* now the actual sorting */
foreach ($parentRecords as $parentData) {
$parentId = $parentData['Section_Id'];
/* now get all children of this parent */
$parentChildren = array();
foreach ($childRecords as $childData) {
if ($childData['Section_Parent'] == $parentId) {
$parentChildren[] = $childData;
}
}
/* now sort the children by Section_Position */
usort($parentChildren, function($a, $b) {
if ($a['Section_Position'] == $b['Section_Position']) {
return 0;
}
return $a['Section_Position'] > $b['Section_Position'] ? 1 : -1;
});
$sorted[] = $parentData;
$sorted = array_merge($sorted, $parentChildren);
}
echo '<pre>' . print_r($sorted, true) . '</pre>';
exit;
OUTPUT:
Array
(
[0] => Array
(
[Section_Id] => 2
[Section_Name] => Section2
[Section_Parent] =>
[Section_Position] => 0
[Section_Depth] => 0
)
[1] => Array
(
[Section_Id] => 5
[Section_Name] => SubSection1ForSection2
[Section_Parent] => 2
[Section_Position] => 0
[Section_Depth] => 1
)
[2] => Array
(
[Section_Id] => 4
[Section_Name] => SubSection2ForSection2
[Section_Parent] => 2
[Section_Position] => 1
[Section_Depth] => 1
)
[3] => Array
(
[Section_Id] => 1
[Section_Name] => Section1
[Section_Parent] =>
[Section_Position] => 1
[Section_Depth] => 0
)
[4] => Array
(
[Section_Id] => 3
[Section_Name] => SubSection1ForSection1
[Section_Parent] => 1
[Section_Position] => 0
[Section_Depth] => 1
)
)
NOTE: first sort is done by respect to parents Section_Position and then to child's Section_Position
U P D A T E
First I want to say sorry to moderators for the long long discussion that we had with #Akorna but I needed to give him this code and I think it will do the job for the future. So #Akorna the code that should work for you is this one:
$inputData = array(
array(
'section_id' => 333,
'section_depth' => 1,
'section_parent' => 332,
'section_position' => 0,
'section_title' => 'Introduction'),
array(
'section_id' => 334,
'section_depth' => 1,
'section_parent' => 332,
'section_position' => 1,
'section_title' => 'Glossary'),
array(
'section_id' => 335,
'section_depth' => 1,
'section_parent' => 332,
'section_position' => 2,
'section_title' => 'Commands'),
array(
'section_id' => 336,
'section_depth' => 1,
'section_parent' => 332,
'section_position' => 3,
'section_title' => 'Components'),
array(
'section_id' => 337,
'section_depth' => 2,
'section_parent' => 336,
'section_position' => 0,
'section_title' => 'Introduction'),
array(
'section_id' => 407,
'section_depth' => 2,
'section_parent' => 401,
'section_position' => 2,
'section_title' => 'Web Application'),
array(
'section_id' => 338,
'section_depth' => 2,
'section_parent' => 336,
'section_position' => 1,
'section_title' => 'AbstractContainer'),
array(
'section_id' => 406,
'section_depth' => 2,
'section_parent' => 401,
'section_position' => 1,
'section_title' => 'Web Application'),
array(
'section_id' => 339,
'section_depth' => 2,
'section_parent' => 336,
'section_position' => 2,
'section_title' => 'ActionsContainer'),
array(
'section_id' => 340,
'section_depth' => 2,
'section_parent' => 336,
'section_position' => 3,
'section_title' => 'BrowserIncompatibility'),
array(
'section_id' => 404,
'section_depth' => 2,
'section_parent' => 402,
'section_position' => 3,
'section_title' => 'Web Application'),
array(
'section_id' => 341,
'section_depth' => 2,
'section_parent' => 336,
'section_position' => 4,
'section_title' => 'CollapsibleContainer'),
array(
'section_id' => 342,
'section_depth' => 2,
'section_parent' => 336,
'section_position' => 5,
'section_title' => 'DetailsContainer'),
array(
'section_id' => 343,
'section_depth' => 2,
'section_parent' => 336,
'section_position' => 6,
'section_title' => 'DynamicMenu'),
array(
'section_id' => 403,
'section_depth' => 2,
'section_parent' => 402,
'section_position' => 1,
'section_title' => 'Web Application'),
array(
'section_id' => 344,
'section_depth' => 2,
'section_parent' => 336,
'section_position' => 7,
'section_title' => 'Settings'),
array(
'section_id' => 345,
'section_depth' => 2,
'section_parent' => 336,
'section_position' => 8,
'section_title' => 'SubfilesViewer'),
array(
'section_id' => 346,
'section_depth' => 2,
'section_parent' => 336,
'section_position' => 9,
'section_title' => 'Taxonomy Management'),
array(
'section_id' => 402,
'section_depth' => 1,
'section_parent' => 400,
'section_position' => 2,
'section_title' => 'Web Application'),
array(
'section_id' => 401,
'section_depth' => 1,
'section_parent' => 400,
'section_position' => 1,
'section_title' => 'Web Application'),
array(
'section_id' => 347,
'section_depth' => 2,
'section_parent' => 336,
'section_position' => 10,
'section_title' => 'UploadQueue'),
array(
'section_id' => 400,
'section_depth' => 0,
'section_parent' => null,
'section_position' => 5,
'section_title' => 'Web Application'),
array(
'section_id' => 332,
'section_depth' => 0,
'section_parent' => null,
'section_position' => 3,
'section_title' => 'Web Application')
);
/* first order by section_depth and then by section_position */
$inputData = array_orderby($inputData, 'section_depth', SORT_ASC, 'section_position', SORT_ASC);
$parents = array();
$sortedByParent = false;
while (!$sortedByParent) {
$elems = array_splice($inputData, count($inputData) - 1, 1);
if (!count($elems)) {
$sortedByParent = true;
$inputData = array_merge($inputData, $parents);
continue;
}
$elem = $elems[0];
if ($elem['section_depth'] == 0) {
if (!isset($elem['children'])) {
$elem['children'] = array();
}
$parents[] = $elem;
} else {
$inputData = put_in_parent($elem, $inputData);
}
}
/* now we have $inputData in nice format like
* parent(child, child, child(child, child(child, child)), child(child(child(child)))),
* parent(child, child, child(child, child(child, child)), child(child(child(child))))
* */
$inputData = merge_children_recursively(array_reverse($inputData));
function merge_children_recursively($inputData) {
$children = array();
foreach ($inputData as $row) {
if (isset($row['children'])) {
/* this ksort call is necessary because the key is actually section_position */
ksort($row['children']);
$rowCopy = $row;
unset($rowCopy['children']);
$children[] = $rowCopy;
$children = array_merge($children, merge_children_recursively($row['children']));
} else {
$children[] = $row;
}
}
return $children;
}
function put_in_parent($elem, $inputData) {
foreach ($inputData as $k => $row) {
if ($row['section_id'] == $elem['section_parent']) {
if (!isset($inputData[$k]['children'])) {
$inputData[$k]['children'] = array();
}
$inputData[$k]['children'][$elem['section_position']] = $elem;
break;
}
}
return $inputData;
}
function array_orderby() {
$args = func_get_args();
$data = array_shift($args);
foreach ($args as $n => $field) {
if (is_string($field)) {
$tmp = array();
foreach ($data as $key => $row) {
$tmp[$key] = $row[$field];
}
$args[$n] = $tmp;
}
}
$args[] = &$data;
call_user_func_array('array_multisort', $args);
return array_pop($args);
}
echo '<pre>' . print_r($inputData, true) . '</pre>';
exit;
I did remove some stuff from the input data so I could orient myself. Just try to give your input data to the logic and let me know what is the result.

Related

Is there a chance that array_slice is bugged - returning wrong

Is there a chance to array_slice is bugged (using PHP 8.0.12)
I were looking for best way to get few elements(limited) of array with possible offset so tried to array_slice but its keep return me wrong index then i expect
I have array with objects from database and they looks like(ill write only id)
$questions simplified to only id
$limit = 1;
$questions = array(
array(
'id' => 2,
'stage' => 1,
'question_order' => 0,
'many_answers' => 0,
'points' => 5.5,
'spread_points_in_time' => 0,
'question' => "Czy Johnny Deep grał Jack'a Sparow'a?",
'time' => "00:00:10"
),
array(
'id' => 3,
'stage' => 1,
'question_order' => 0,
'many_answers' => 0,
'points' => 4.5,
'spread_points_in_time' =>0,
'question' => "Producent laptopa Darka",
'time' => "00:00:00"
),
array(
'id' => 1,
'stage' => 1,
'question_order' => 0,
'many_answers' => 0,
'points' => 10,
'spread_points_in_time' => 0,
'question' => "Która klawiatura jest mechniczna",
'time' => "00:00:10"
),
array(
'id' => 8,
'stage' => 2,
'question_order' => 0,
'many_answers' => 0,
'points' => 30,
'spread_points_in_time' => 1,
'question' => "2*2",
'time' => "00:00:30"
),
array(
'id' => 4,
'stage' => 2,
'question_order' => 0,
'many_answers' => 0,
'points' => 30,
'spread_points_in_time' => 0,
'question' => "Który język programowania ma dostęp do komórek pamięci komputera?",
'time' => "00:00:30"
),
array(
'id' => 7,
'stage' => 2,
'question_order' => 0,
'many_answers' => 0,
'points' => 30,
'spread_points_in_time' => 0,
'question' => "2+2",
'time' => "00:00:30"
),
array(
'id' => 10,
'stage' => 3,
'question_order' => 1,
'many_answers' => 1,
'points' => 5,
'spread_points_in_time' => 0,
'question' => "Jaki jest symbol chemiczny srebra?",
'time' => "00:00:00"
),
array(
'id' => 11,
'stage' => 3,
'question_order' => 0,
'many_answers' => 1,
'points' => 5,
'spread_points_in_time' => 0,
'question' => "Jaka jest żywotność ważki?",
'time' => "00:00:00"
),
array(
'id' => 9,
'stage' => 3,
'question_order' => 0,
'many_answers' => 0,
'points' => 5,
'spread_points_in_time' => 0,
'question' => "W którym roku Titanic zatonął na Oceanie Atlantyckim 15 kwietnia podczas dziewiczej podróży z Southampton?",
'time' => "00:00:00"
)
);
echo json_encode(
array(
'all' => $questions,
'limit' => $limit,
'sliced' => array_slice($questions, 0, $limit),
)
);
so when i try array_splice(array, 0, 1) i would expect 1 so id should be 2 but instead i get object which have id 1
i also tried with flag to keep indexed but then i end up same but with true index of object with id 1 (then key is 2)
If i put limit as 2 then i get object with id 1 and also object with id 2 (flag to keep indexed also return me properly to objects 2 and 0)
Also tried to remove id from every object by
foreach($questions as $key => $question)
{
unset($questions[$key]['id'];
}
But this didnt changed anything
$questions source https://pastebin.com/wDfJdm9Z
After plenty of combinations i figured it out
I were sorting this array before everything with forcing keys
So in sorting it looked like
foreach($toSort as $key => $item)
{
foreach($ids as $idKey => $id)
{
if($item['id'] == $id)
{
$sorted[$idKey] = $item;
break;
}
}
}
So for example array could end up with wrong order of keys like:
array(
[1] => item2,
[0] => item1,
[2] => item3
);
I were expecting array gona shove key 0 to be index 0 but don't looks like
Setting something to exact key isn't same as set something to set at exact index
SOLUTION WAS add ksort($sorted) before return $sorted

Counting expenses for categories stored in tree like array

I have an app where users can store their expenses and assign it to categories. Categories have tree structure, without depth limit and users can assign expense to any category (children, parent or middle). What I want to do is to count sum of expenses for all categories in tree structure. Lets simplify things and assume I have array with categories:
$categories = [
0 => [
'id' => 1,
'name' => 'Car',
'expenses_sum' => 0,
'subcategories' => [
0 => [
'id' => 2,
'name' => 'Gas',
'expenses_sum' => 0,
'subcategories' => [
0 => [
'id' => 3,
'name' => 'Orlen',
'expenses_sum' => 300,
'subcategories' => [
0 => [
'id' => 4,
'name' => 'Orlen A',
'expenses_sum' => 100,
'subcategories' => []
],
1 => [
'id' => 5,
'name' => 'Orlen B',
'expenses_sum' => 100,
'subcategories' => []
],
],
],
],
],
],
],
];
What I want do do is to go to the deepest level ("Orlen A" and "Orlen B"), sum expenses from that level, add it to the parent level ("Orlen") and store as the new "expenses_sum", so it should be: 100 + 100 + 300 = 500 and repeat it to the top level.
My code to do that looks like this:
function sumCategory(&$category) {
if (isset($category['subcategories'])) {
foreach ($category['subcategories'] as $subCategory) {
$subCategory['expenses_sum'] = sumCategory($subCategory);
$category['expenses_sum'] += $subCategory['expenses_sum'];
}
}
return $category['expenses_sum'];
}
foreach ($categories as $index => $category) {
$categories[$index]['expenses_sum'] = sumCategory($category);
}
echo '<pre>';
print_r($categories);
echo '</pre>';
Code counts properly sum at all levels, but the problem is that finally I got $categories array with modfied only "expenses_sum" at the top level and categories in the middle stays not modified. I tried to pass $categories to function by refference, but it doesnt help. Any tips what should I correct?
I have simplified problem, so you can easily grab all above code to test things on your own.
To clarify things: at the end I expect my array will be as follow:
$categories = [
0 => [
'id' => 1,
'name' => 'Car',
'expenses_sum' => 500, //500 + 0
'subcategories' => [
0 => [
'id' => 2,
'name' => 'Gas',
'expenses_sum' => 500, //500 + 0
'subcategories' => [
0 => [
'id' => 3,
'name' => 'Orlen',
'expenses_sum' => 500, //100 + 100 + 300
'subcategories' => [
0 => [
'id' => 4,
'name' => 'Orlen A',
'expenses_sum' => 100,
'subcategories' => []
],
1 => [
'id' => 5,
'name' => 'Orlen B',
'expenses_sum' => 100,
'subcategories' => []
],
],
],
],
],
],
],
];
$categories = [
0 => [
'id' => 1,
'name' => 'Car',
'expenses_sum' => 0,
'subcategories' => [
0 => [
'id' => 2,
'name' => 'Gas',
'expenses_sum' => 0,
'subcategories' => [
0 => [
'id' => 3,
'name' => 'Orlen',
'expenses_sum' => 300,
'subcategories' => [
0 => [
'id' => 4,
'name' => 'Orlen A',
'expenses_sum' => 100,
'subcategories' => []
],
1 => [
'id' => 5,
'name' => 'Orlen B',
'expenses_sum' => 100,
'subcategories' => []
],
],
],
],
],
],
],
];
function expensesSum($category) {
$sum = $category['expenses_sum'] ;
foreach($category['subcategories'] as $subCategory) {
$sum += expensesSum($subCategory);
}
return $sum;
}
function calculateExpenses(&$categories) {
foreach($categories as $index => $category) {
// do subs first
calculateExpenses($categories[$index]['subcategories']);
// then parent
$categories[$index]['expenses_sum'] = expensesSum($category);
}
return $categories;
}
print_r(calculateExpenses($categories));
Output:
Array
(
[0] => Array
(
[id] => 1
[name] => Car
[expenses_sum] => 500
[subcategories] => Array
(
[0] => Array
(
[id] => 2
[name] => Gas
[expenses_sum] => 500
[subcategories] => Array
(
[0] => Array
(
[id] => 3
[name] => Orlen
[expenses_sum] => 500
[subcategories] => Array
(
[0] => Array
(
[id] => 4
[name] => Orlen A
[expenses_sum] => 100
[subcategories] => Array
(
)
)
[1] => Array
(
[id] => 5
[name] => Orlen B
[expenses_sum] => 100
[subcategories] => Array
(
)
)
)
)
)
)
)
)
)
function calculateExpenses($categories) {
$expenses = 0;
foreach($categories as $category) {
$expenses += $category['expenses_sum'];
$expenses += calculateExpenses($category['subcategories']);
}
return $expenses;
}
echo calculateExpenses($categories);

Make unique array and add the amount in php

I have to make the array to unique array list if the invoice_products_id is same and for the same invoice_products_id i have add the amount. I am able to make it unique but amount is not adding.
0 =>{
'id' => 9,
'invoice_products_id' => 2,
'amount' => 1.8,
},
1 =>{
'id' => 10,
'invoice_products_id' => 3,
'amount' => 2,
},
2 =>{
'id' => 11,
'invoice_products_id' => 2,
'amount' => 1.1,
},
3 =>{
'id' => 12,
'invoice_products_id' => 3,
'amount' => 1.2,
},
code:
$invtax=[];
foreach($invoiceProduct['invoice_taxes'] as $taxkey=>$taxval){
$ref=$taxval->invoice_products_id;
if(isset($invtax[$ref])){
$invtax[$ref]->amount+=$taxval->amount;
}else{
$invtax[$ref]=$taxval;
}
}
result:
2 =>{
'id' => 11,
'invoice_products_id' => 2,
'amount' => 2.9,
},
3 =>{
'id' => 12,
'invoice_products_id' => 3,
'amount' => 1.2,
},
expected:
2 =>{
'id' => 11,
'invoice_products_id' => 2,
'amount' => 2.9,
},
3 =>{
'id' => 12,
'invoice_products_id' => 3,
'amount' => 3.2,
},
Making use of array_filter and array_walk functions
See here for live example: https://3v4l.org/rXXR9
Input
<?php
$arr = [
[
'id' => 9,
'invoice_products_id' => 2,
'amount' => 1.8,
],[
'id' => 10,
'invoice_products_id' => 3,
'amount' => 2,
],[
'id' => 11,
'invoice_products_id' => 2,
'amount' => 1.1,
],[
'id' => 12,
'invoice_products_id' => 3,
'amount' => 1.2,
],
];
Program
<?php
$assorted_heap = [];
$filter_function = function($v, $k) {
global $assorted_heap;
if (isset($assorted_heap[$v['invoice_products_id']])) {
$assorted_heap[$v['invoice_products_id']][1] += $v['amount'];
return false;
} else {
$assorted_heap[$v['invoice_products_id']] = [$k, $v['amount']];
}
return true;
};
$walk_function = function(&$v, $k) {
global $assorted_heap;
$v['amount'] = $assorted_heap[$v['invoice_products_id']][1];
};
$new_arr = array_filter($arr,
$filter_function,
ARRAY_FILTER_USE_BOTH
);
array_walk($new_arr, $walk_function);
unset($assorted_heap);
print_r($new_arr);
Output
Array
(
[0] => Array
(
[id] => 9
[invoice_products_id] => 2
[amount] => 2.9
)
[1] => Array
(
[id] => 10
[invoice_products_id] => 3
[amount] => 3.2
)
)

Create a function to output a category hierarchy into a select drop down form input by passing the $categories array to the function

Create a function to output a category hierarchy into a select drop down form input by passing the $categories array to the function.
The given set array of data:
$categories = array(
1 => array(‘id’ => 5,‘name’ => ‘Fruits’,‘sort’ => 0,‘parent’ => 0),
2 => array(‘id’ => 6, ‘name’ => ‘Donuts’,‘sort’ => 1,‘parent’ => 7),
3 => array(‘id’ => 7, ‘name’ => ‘Hard Candy’,‘sort’ => 0,‘parent’ => 11),
4 => array(‘id’ => 8, ‘name’ => ‘Pears’,‘sort’ => 3,‘parent’ => 1),
5 => array(‘id’ => 9, ‘name’ => ‘Apples’,‘sort’ => 1,‘parent’ =>1),
6 => array(‘id’ => 18, ‘name’ => ‘Oranges’,‘sort’ => 4,‘parent’ => 1),
7 => array(‘id’ => 19, ‘name’ => ‘Sweets’,‘sort’ => 2,‘parent’ => 0),
8 => array(‘id’ => 20, ‘name’ => ‘Red Delicious’,‘sort’ => 5,‘parent’ => 5),
9 => array(‘id’ => 21, ‘name’ => ‘Granny Smith Apples’,‘sort’ => 8,‘parent’ => 5),
10 => array(‘id’ => 10, ‘name’ => ‘Gummy Bears’,‘sort’ =>5,‘parent’ => 7),
11 => array(‘id’ => 11, ‘name’ => ‘Candy’,‘sort’ => 8,‘parent’ => 7),
12 => array(‘id’ => 12, ‘name’ => ‘Vegetables’,‘sort’ => 3,‘parent’ => 0),
12 => array(‘id’ => 13, ‘name’ => ‘Yellow’,‘sort’ => 2,‘parent’ => 16),
14 => array(‘id’ => 14, ‘name’ => ‘Grean Beans’,‘sort’ => 11,‘parent’ => 12),
15 => array(‘id’ => 15, ‘name’ => ‘Broccoli’,‘sort’ => 10,‘parent’ =>12),
16 => array(‘id’ => 16, ‘name’ => ‘Corn’,‘sort’ => 14,‘parent’ => 12),
17 => array(‘id’ => 17, ‘name’ => ‘White’,‘sort’ => 1,‘parent’ => 16)
);
Note: Use recursive function if can.
Output should like this:
<select>
<option>Fruits</option>
<option>-Apples</option>
<option>--Red Delicious Apples</option>
<option>--Granny Smith Apples</option>
<option>-Pears</option>
<option>-Organges</option>
<option>Sweets</option>
<option>-Donuts</option>
<option>-Gummy Bears</option>
<option>-Candy</option>
<option>--Hard Candy</option>
<option>Vegetables</option>
<option>-Broccoli</option>
<option>-Grean Beans</option>
<option>-Corn</option>
<option>--White</option>
<option>--Yellow</option>
</select>
I got the drop down of the products based on the category. But i couldn't do with the sorting order
<?php
function array_msort($array, $cols)
{
$colarr = array();
foreach ($cols as $col => $order) {
$colarr[$col] = array();
foreach ($array as $k => $row) { $colarr[$col]['_'.$k] = strtolower($row[$col]); }
}
$eval = 'array_multisort(';
foreach ($cols as $col => $order) {
$eval .= '$colarr[\''.$col.'\'],'.$order.',';
}
$eval = substr($eval,0,-1).');';
eval($eval);
$ret = array();
foreach ($colarr as $col => $arr) {
foreach ($arr as $k => $v) {
$k = substr($k,1);
if (!isset($ret[$k])) $ret[$k] = $array[$k];
$ret[$k][$col] = $array[$k][$col];
}
}
return $ret;
}
$categories = array(
1 => array('id' => 5,'name' => 'Fruits','sort' => 0,'parent' => 0),
2 => array('id' => 6, 'name' => 'Donuts','sort' => 1,'parent' => 7),
3 => array('id' => 7, 'name' => 'Hard Candy','sort' => 0,'parent' => 11),
4 => array('id' => 8, 'name' => 'Pears','sort' => 3,'parent' => 1),
5 => array('id' => 9, 'name' => 'Apples','sort' => 1,'parent' =>1),
6 => array('id' => 18, 'name' => 'Oranges','sort' => 4,'parent' => 1),
7 => array('id' => 19, 'name' => 'Sweets','sort' => 2,'parent' => 0),
8 => array('id' => 20, 'name' => 'Red Delicious','sort' => 5,'parent' => 5),
9 => array('id' => 21, 'name' => 'Granny Smith Apples','sort' => 8,'parent' => 5),
10 => array('id' => 10, 'name' => 'Gummy Bears','sort' =>5,'parent' => 7),
11 => array('id' => 11, 'name' => 'Candy','sort' => 8,'parent' => 7),
12 => array('id' => 12, 'name' => 'Vegetables','sort' => 3,'parent' => 0),
13 => array('id' => 13, 'name' => 'Yellow','sort' => 2,'parent' => 16),
14 => array('id' => 14, 'name' => 'Grean Beans','sort' => 11,'parent' => 12),
15 => array('id' => 15, 'name' => 'Broccoli','sort' => 10,'parent' =>12),
16 => array('id' => 16, 'name' => 'Corn','sort' => 14,'parent' => 12),
17 => array('id' => 17, 'name' => 'White','sort' => 1,'parent' => 16));
$arr2 = array_msort($categories, array('parent'=>SORT_ASC, 'sort'=>SORT_ASC));
for($i=count($arr2);$i>=1;$i--)
{
if($arr2[$i])
{
$cnt=0;
for($j=count($arr2);$j>=1;$j--)
{
if($arr2[$j] && $arr2[$j]['parent']==$i)
{
$arr2[$i]['child'][$cnt]['key'] = $arr2[$j]['id'];
$arr2[$i]['child'][$cnt] = $arr2[$j];
$arr2[$j] = '';
$cnt++;
}
}
}
}
$res = array();
$n =0;
$res_arr = array_filter($arr2);
for($i=1;$i<=count($arr2);$i++)
{
if($arr2[$i]!='')
{
$res[$n] = $arr2[$i];
$n++;
}
}
$res_arr = array_filter($arr2);
$str = '';
function fntest($arr, $str, $level='')
{
for($i=0;$i<=count($arr);$i++)
{
if(isset($arr[$i]))
{
echo '<option>'.$level.$arr[$i]['name'].'</option>';
if(isset($arr[$i]) && is_array($arr[$i]) && array_key_exists('child', $arr[$i]))
{
$level1 = $level.'-';
fntest($arr[$i]['child'], $str,$level1);
}
}
}
return $str;
}
echo '<select>';
fntest($res, $str,'');
echo '</select>';
?>

PHP Arrays, appending depth of array item recursively to an array with the key of 'depth'

Per the example array at the very bottom, i want to be able to append the depth of each embedded array inside of the array. for example:
array (
53 =>
array (
'title' => 'Home',
'path' => '',
'type' => '118',
'pid' => 52,
'hasChildren' => 0,
),
Has a depth of one according to the sample array shown below so it should now look like this:
array (
53 =>
array (
'title' => 'Home',
'path' => '',
'type' => '118',
'pid' => 52,
'hasChildren' => 0,
'depth' => 1,
),
and so on...
All of the recursive array function attempts i have made are pretty embarrassing. However I have looked at RecursiveArrayIterator which has the getDepth function. I'm confused on how to append it to the current array... any help is VERY much appreciated, thank you.
array (
'title' => 'Website Navigation',
'path' => '',
'type' => '115',
'pid' => 0,
'hasChildren' => 1,
'children' =>
array (
53 =>
array (
'title' => 'Home',
'path' => '',
'type' => '118',
'pid' => 52,
'hasChildren' => 0,
),
54 =>
array (
'title' => 'Features',
'path' => 'features',
'type' => '374',
'pid' => 52,
'hasChildren' => 1,
'children' =>
array (
59 =>
array (
'title' => 'artistic',
'path' => 'features/artistic',
'type' => '374',
'pid' => 54,
'hasChildren' => 1,
'children' =>
array (
63 =>
array (
'title' => 'galleries',
'path' => 'features/artistic/galleries',
'type' => '374',
'pid' => 59,
'hasChildren' => 1,
'children' =>
array (
65 =>
array (
'title' => 'graphics',
'path' => 'features/artistic/galleries/graphics',
'type' => '118',
'pid' => 63,
'hasChildren' => 0,
),
67 =>
array (
'title' => 'mixed medium',
'path' => 'features/artistic/galleries/mixed-medium',
'type' => '118',
'pid' => 63,
'hasChildren' => 0,
),
64 =>
array (
'title' => 'overview',
'path' => 'features/artistic/galleries',
'type' => '118',
'pid' => 63,
'hasChildren' => 0,
),
68 =>
array (
'title' => 'photography',
'path' => 'features/artistic/galleries/photography',
'type' => '118',
'pid' => 63,
'hasChildren' => 0,
),
66 =>
array (
'title' => 'traditional',
'path' => 'features/artistic/galleries/traditional',
'type' => '118',
'pid' => 63,
'hasChildren' => 0,
),
),
),
62 =>
array (
'title' => 'overview',
'path' => 'features/artistic',
'type' => '118',
'pid' => 59,
'hasChildren' => 0,
),
69 =>
array (
'title' => 'tutorials',
'path' => 'features/artistic/tutorials',
'type' => '374',
'pid' => 59,
'hasChildren' => 1,
'children' =>
array (
71 =>
array (
'title' => 'by category',
'path' => 'features/artistic/tutorials/by-category/',
'type' => '118',
'pid' => 69,
'hasChildren' => 0,
),
72 =>
array (
'title' => 'by date',
'path' => 'features/artistic/tutorials/by-date/',
'type' => '118',
'pid' => 69,
'hasChildren' => 0,
),
70 =>
array (
'title' => 'overview',
'path' => 'features/artistic/tutorials',
'type' => '118',
'pid' => 69,
'hasChildren' => 0,
),
),
),
),
),
58 =>
array (
'title' => 'overview',
'path' => 'features',
'type' => '118',
'pid' => 54,
'hasChildren' => 0,
),
61 =>
array (
'title' => 'projects / labs',
'path' => 'features/projects-labs/',
'type' => '374',
'pid' => 54,
'hasChildren' => 0,
),
60 =>
array (
'title' => 'web development',
'path' => 'features/web-development',
'type' => '374',
'pid' => 54,
'hasChildren' => 1,
'children' =>
array (
74 =>
array (
'title' => 'articles',
'path' => 'features/web-development/articles/',
'type' => '374',
'pid' => 60,
'hasChildren' => 0,
),
73 =>
array (
'title' => 'overview',
'path' => 'features/web-development',
'type' => '118',
'pid' => 60,
'hasChildren' => 0,
),
75 =>
array (
'title' => 'tutorials',
'path' => 'features/web-development/tutorials',
'type' => '374',
'pid' => 60,
'hasChildren' => 0,
),
),
),
),
),
55 =>
array (
'title' => 'Activity',
'path' => 'activity',
'type' => '374',
'pid' => 52,
'hasChildren' => 0,
),
56 =>
array (
'title' => 'Blog',
'path' => 'blog',
'type' => '374',
'pid' => 52,
'hasChildren' => 0,
),
57 =>
array (
'title' => 'About',
'path' => 'about',
'type' => '374',
'pid' => 52,
'hasChildren' => 1,
'children' =>
array (
76 =>
array (
'title' => 'the author',
'path' => 'about/the-author',
'type' => '118',
'pid' => 57,
'hasChildren' => 0,
),
77 =>
array (
'title' => 'the website',
'path' => 'about/the-website',
'type' => '118',
'pid' => 57,
'hasChildren' => 0,
),
),
),
),
),
);
print_r($example);
?>
I assume there is another array( at the top not included in your example code.
Something like this?
function array_set_depth($array, $depth = -1)
{
$subdepth = $depth + 1;
if ($depth < 0) {
foreach ($array as $key => $subarray) {
$temp[$key] = array_set_depth(($subarray), $subdepth);
}
}
if ($array['hasChildren'] && isset($array['children'])) {
foreach ($array['children'] as $key => $subarray) {
$temp[$key] = array_set_depth($subarray, $subdepth);
}
$array['children'] = $temp;
}
$array['depth'] = $depth;
return $array;
}
Example usage, I set your array to the value $a:
$b = array_set_depth($a);
print_r($b);
Edit:
To set depth before the children for nice printing you can do this:
function array_set_depth($array, $depth = -1)
{
$subdepth = $depth + 1;
if ($depth < 0) {
foreach ($array as $key => $subarray) {
$temp[$key] = array_set_depth(($subarray), $subdepth);
}
return $temp;
}
$array['depth'] = $depth;
if ($array['hasChildren'] && isset($array['children'])) {
foreach ($array['children'] as $key => $subarray) {
$temp[$key] = array_set_depth($subarray, $subdepth);
}
unset($array['children']);
$array['children'] = $temp;
}
return $array;
}
A recursive function like this should do it?
function setDepth(&$a, $depth)
{
$a['depth']=$depth;
foreach($a as $key=>$value)
{
if (is_array($value))
setDepth($a[$key], $depth+1);
}
}
The thing to note is that the array is passed by reference, so that we can modify it. Note that we also use this reference in the recursive call to setDepth. Although I used foreach for convenience, the $value variable is a copy, and passing that to setDepth would only make short lived changes within the scope of the foreach loop.
Modified Pauls code to work with this example.
function setDepth(&$a, $depth = -1)
{
if (($depth > -1) && !($depth % 2))
$a['depth']= $depth / 2;
foreach($a as $key=>$value)
{
if (is_array($value))
setDepth($a[$key], $depth+1);
}
}
setDepth($a);
print_r($a);
sth like this should do the trick:
function setdepth($arr, $depth = 0)
{
foreach ($arr as $key => $val)
{
$arr[$key]['depth'] = $depth;
if ($arr[$key]['hasChildren'])
{
setdepth(&$arr[$key]['children'], $depth+1);
}
}
}
i would be easier if your array started with index not with values, so example usage could be like this:
$arr[0] = $website;
setdepth(&$arr, 0);
where website is the array from your example
This might be helpful:
function extend( $arr, $myArr=array() ) {
foreach( $arr as $key => $value ) {
if( is_array( $key ) ) {
extend( $arr[ $key ] );
} else {
$myArr[ $key ] = $arr[ $key ];
}
}
return $myArr;
}
Function called "extend" because it's not only copies array into new one, it can also extends existing arrays.
To extend an array you should put it as the second parameter, otherwise put an empty array.
The function lopps through array properties and checks is it an array or not and if it is function envoked again otherwise it copies values into another array and returns it.

Categories