Related
I have an array stored as $product_categories. A sample of this array is:
$array = [
[
['id' => 10, 'text' => 'Latex'],
['id' => 15, 'text' => 'Occasion Latex'],
['id' => 82, 'text' => 'Christmas'],
],
[
['id' => 11, 'text' => 'Accessories'],
['id' => 97, 'text' => 'Retail Accessories'],
['id' => 558, 'text' => 'Super Stuffer'],
],
[
['id' => 374, 'text' => 'Party Supplies'],
['id' => 1488, 'text' => 'Party by Occasion'],
['id' => 1493, 'text' => 'Christmas'],
],
];
I want to sort it ONLY by the key 'text' in [0], which would give me a result of
[
[
['id' => 11, 'text' => 'Accessories'],
['id' => 97, 'text' => 'Retail Accessories'],
['id' => 558, 'text' => 'Super Stuffer'],
],
[
['id' => 10, 'text' => 'Latex'],
['id' => 15, 'text' => 'Occasion Latex'],
['id' => 82, 'text' => 'Christmas'],
],
[
['id' => 374, 'text' => 'Party Supplies'],
['id' => 1488, 'text' => 'Party by Occasion'],
['id' => 1493, 'text' => 'Christmas'],
],
];
I've tried using
$product_categories = usort($product_categories, 'sortAlphabetically');
function sortAlphabetically($a, $b) {
return strcmp($a['text'], $b['text']);
}
Using that, a print_r() of the array simply returns
1.
I thought usort() was the correct way to sort the array but clearly I'm doing something wrong here.
You only need to access the subarray data using array syntax as you've expressed in English. (Demo)
usort(
$array,
function($a, $b) {
return $a[0]['text'] <=> $b[0]['text'];
}
);
var_export($array);
Or in PHP7.4 or higher:
usort($array, fn($a, $b) => $a[0]['text'] <=> $b[0]['text']);
Your array:
$array = [
'0' => [
'0' => [
'id' => 10,
'text' => 'Latex',
],
'1' => [
'id' => 15,
'text' => 'Occasion Latex',
],
'2' => [
'id' => 82,
'text' => 'Christmas',
],
],
'1' => [
'0' => [
'id' => 11,
'text' => 'Accessories',
],
'1' => [
'id' => 97,
'text' => 'Retail Accessories',
],
'2' => [
'id' => 558,
'text' => 'Super Stuffer',
],
],
'2' => [
'0' => [
'id' => 374,
'text' => 'Party Supplies',
],
'1' => [
'id' => 1488,
'text' => 'Party by Occasion',
],
'2' => [
'id' => 1493,
'text' => 'Christmas',
],
],
];
The sort:
// uasort(): "Sort an array with a user-defined comparison function
// and maintain index association"
uasort($array, function (array $a, array $b) {
// "I want to sort it ONLY by the key 'text' in [0]"
// Get first from array (aka [0]).
// (You could change that to fix $a[0] and $b[0] if you want|need to.)
$aFirst = reset($a);
$bFirst = reset($b);
$offset = 'text';
if ($aFirst[$offset] == $bFirst[$offset]) {
return 0;
}
// a < b === asc ; a > b === desc
return ($aFirst[$offset] < $bFirst[$offset]) ? -1 : 1;
});
echo var_export($array, true) . PHP_EOL;
Results in:
[
1 => [
0 => [
'id' => 11,
'text' => 'Accessories',
],
1 => [
'id' => 97,
'text' => 'Retail Accessories',
],
2 => [
'id' => 558,
'text' => 'Super Stuffer',
],
],
0 => [
0 => [
'id' => 10,
'text' => 'Latex',
],
1 => [
'id' => 15,
'text' => 'Occasion Latex',
],
2 => [
'id' => 82,
'text' => 'Christmas',
],
],
2 => [
0 => [
'id' => 374,
'text' => 'Party Supplies',
],
1 => [
'id' => 1488,
'text' => 'Party by Occasion',
],
2 => [
'id' => 1493,
'text' => 'Christmas',
],
],
]
I have the following array:
$products = [
[
'id' => 21,
'name' => 'Floral Dress',
'params' => [
'size' => 14,
'price' => 23.99,
'department' => 'Dresses'
]
],
[
'id' => 413,
'name' => 'Maxi Skirt',
'params' => [
'size' => 10,
'price' => 12.99,
'department' => 'Skirts'
]
],
[
'id' => 78,
'name' => 'A Line Prom Dress',
'params' => [
'size' => 10,
'price' => 79.99,
'department' => 'Dresses'
]
],
[
'id' => 212,
'name' => 'Nude Block High Heels',
'params' => [
'size' => 6,
'price' => 20.99,
'department' => 'Shoes'
]
],
[
'id' => 54,
'name' => 'Denim Trim Dress',
'params' => [
'size' => 8,
'price' => 52.99,
'department' => 'Dresses'
]
],
];
Unfortunately I cannot control how the array is built.
Instead I need to restructure the data so that the array is sorted by the ['params']['department'] key.
So ideally I would take the above and output it like so:
$products = [
'Dresses' => [
[
'id' => 21,
'name' => 'Floral Dress',
'params' => [
'size' => 14,
'price' => 23.99
]
],
[
'id' => 78,
'name' => 'A Line Prom Dress',
'params' => [
'size' => 10,
'price' => 79.99
]
],
[
'id' => 54,
'name' => 'Denim Trim Dress',
'params' => [
'size' => 8,
'price' => 52.99
]
],
],
'Skirts' => [
[
'id' => 413,
'name' => 'Maxi Skirt',
'params' => [
'size' => 10,
'price' => 12.99
]
],
],
'Shoes' => [
[
'id' => 212,
'name' => 'Nude Block High Heels',
'params' => [
'size' => 6,
'price' => 20.99
]
],
]
You could simply iterate over all the products and populate a new associative array holding the departments, which are themselves arrays of corresponding products. See the comments in the code below.
<?php
// same data as in the question, just in one line for better overview
$products = [['id' => 21,'name' => 'Floral Dress','params' => ['size' => 14,'price' => 23.99,'department' => 'Dresses']],['id' => 413,'name' => 'Maxi Skirt','params' => ['size' => 10,'price' => 12.99,'department' => 'Skirts']],['id' => 78,'name' => 'A Line Prom Dress','params' => ['size' => 10,'price' => 79.99,'department' => 'Dresses']],['id' => 212,'name' => 'Nude Block High Heels','params' => ['size' => 6,'price' => 20.99,'department' => 'Shoes']],['id' => 54,'name' => 'Denim Trim Dress','params' => ['size' => 8,'price' => 52.99,'department' => 'Dresses']]];
// initialize empty department array
$departments = array();
// iterate over all the products
foreach ( $products as $product ) {
// get this product's department
$product_department = $product['params']['department'];
// unset the department in the params array
unset( $product['params']['department'] );
// initialize this department as an empty array
// if it doesn't exist yet
if ( !isset( $departments[$product_department] ) ) {
$departments[$product_department] = array();
}
// push this product in its corresponding department
$departments[$product_department][] = $product;
}
var_dump( $departments );
$groupedProducts = [];
foreach ($products as &$product) {
$department = $product['params']['department'];
unset($product['params']['department']);
$groupedProducts[$department] = $product;
}
var_dump($groupedProducts);
I have a nested array with a structure as detailed below.
It is an org chart where an employ could have other employees related:
$tree_array = [
[
'id' => 1,
'employee' => 'John',
'leader_id' => NULL,
'team' => [
[
'id' => 2,
'employee' => 'Maria',
'leader_id' => 1,
'team' => [],
],
[
'id' => 3,
'employee' => 'Kevin',
'leader_id' => 1,
'team' => [
[
'id' => 4,
'employee' => 'Alan',
'leader_id' => 3,
'team' => [],
],
[
'id' => 5,
'employee' => 'Bret',
'leader_id' => 3,
'team' => [],
],
],
],
],
]
];
Every node has an ID and a team, that could be an array of other nodes and so on.
I need to obtain each node in a flat array, like this structure:
$flat_array = array(
array(
'id' => 1,
'employee' => 'John',
'leader_id' => NULL
),
array(
'id' => 2,
'employee' => 'Maria',
'leader_id' => 1
),
array(
'id' => 3,
'employee' => 'Kevin',
'leader_id' => 1
),
...
);
I've tried to implement a recursive function, but I get only the nodes of the last iteration.
Any help?
You can make a recursive function, like this:
function flatten($arr, $final=array()) {
foreach($arr as $a) {
$tmp = $a;
unset($tmp['team']);
$final[]= $tmp;
if ($a['team'] && count($a['team']) > 0) $final = flatten($a['team'], $final);
}
return $final;
}
$flat =flatten($tree_array);
Test it here: https://www.tehplayground.com/UHWCccFIkrS5v75Z
$menus = [
0 => [
'id' => 'home',
'title' => 'Home',
'url' => '/display/home',
'children' => [],
'parent' => null
],
1 => [
'id' => 'nodes',
'title' => 'Nodes',
'url' => 'nodes/index',
'children' => [
0 => [
'id' => 'addNode',
'title' => 'Add Node',
'url' => '/nodes/add',
'children' => [],
'parent' => "nodes"
],
1 => [
'id' => 'editNode',
'title' => 'Edit Node',
'url' => '/nodes/edit',
'children' => [],
'parent' => 'nodes'
],
2 => [
'id' => 'deleteNode',
'title' => 'Delete Node',
'url' => '/nodes/delete',
'children' => [
0 => [
'id' => 'deleteMultipleNodes',
'title' => 'Delete Multiple Nodes',
'url' => '/nodes/deleteall',
'children' => [
0 => [
'id' => 'deleteMultipleSelectedNodes',
'title' => 'Delete Multiple Selected Nodes',
'url' => '/nodes/deleteallselected',
'children' => [],
'parent' => 'deleteMultipleNodes'
]
],
'parent' => 'deleteNode'
]
],
'parent' => 'nodes'
]
],
'parent' => null
]
];
Assuming I have this array. What i want is to recursively search this array for an "id" and if found push a new children to the children array of that element.
I've tried it via different ways, I've also tried to use RecursiveArrayIterator to traverse the array, but the problem is how can i push value to that index of the array when found while traversing.
For Example here is a code from one of my tries:
private function traverseArray($array)
{
$child = [
'id' => 'deleteMultipleNotSelectedNodes',
'title' => 'Delete Multiple Not Selected Nodes',
'url' => '/nodes/deletenotselected',
'children' => [],
'parent' => 'deleteMultipleNodes'
];
foreach($array as $key=>$value)
{
if(is_array($value))
{
$this->traverseArray($value);
}
if($key == "id" && $value == "deleteMultipleNodes")
{
array_push($array["children"], $child); // This part is confusing me, How to add the child on this index where the id is found.
}
}
}
Any help on how to do such thing in an efficient way would save my days.
Here it's how it would work without using $this and fixing bugs in comparing $value instead assigning anything to value.
Please note the difference with &$array and &$value, which are references, so it would change the original data instead of copying it into new variables.
<?php
$menus = [
0 => [
'id' => 'home',
'title' => 'Home',
'url' => '/display/home',
'children' => [],
'parent' => null
],
1 => [
'id' => 'nodes',
'title' => 'Nodes',
'url' => 'nodes/index',
'children' => [
0 => [
'id' => 'addNode',
'title' => 'Add Node',
'url' => '/nodes/add',
'children' => [],
'parent' => "nodes"
],
1 => [
'id' => 'editNode',
'title' => 'Edit Node',
'url' => '/nodes/edit',
'children' => [],
'parent' => 'nodes'
],
2 => [
'id' => 'deleteNode',
'title' => 'Delete Node',
'url' => '/nodes/delete',
'children' => [
0 => [
'id' => 'deleteMultipleNodes',
'title' => 'Delete Multiple Nodes',
'url' => '/nodes/deleteall',
'children' => [
0 => [
'id' => 'deleteMultipleSelectedNodes',
'title' => 'Delete Multiple Selected Nodes',
'url' => '/nodes/deleteallselected',
'children' => [],
'parent' => 'deleteMultipleNodes'
]
],
'parent' => 'deleteNode'
]
],
'parent' => 'nodes'
]
],
'parent' => null
]
];
function traverseArray(&$array)
{
$child = [
'id' => 'deleteMultipleNotSelectedNodes',
'title' => 'Delete Multiple Not Selected Nodes',
'url' => '/nodes/deletenotselected',
'children' => [],
'parent' => 'deleteMultipleNodes'
];
foreach($array as $key=>&$value)
{
if(is_array($value))
{
traverseArray($value);
}
if($key == "id" && $value == "deleteMultipleNodes")
{
array_push($array["children"], $child);
}
}
}
echo "=== before \n";
var_export($menus);
echo "\n\n";
traverseArray($menus);
echo "=== after \n";
var_export($menus);
I've been stuck trying to figure this out for a week now. I have an array in the following format:
[
1 => [
'name' => 'Maths',
'parent_category_id' => NULL
],
2 => [
'name' => 'Algebra',
'parent_category_id' => 1
],
3 => [
'name' => 'Expanding brackets',
'parent_category_id' => 2
],
4 => [
'name' => 'Factorising brackets',
'parent_category_id' => 2
],
5 => [
'name' => 'English',
'parent_category_id' => NULL
],
6 => [
'name' => 'Shakespeare',
'parent_category_id' => 5
]
]
and I want to transform it into an array in this format:
[
'Maths' => [
'category_id' => 1,
'questions' => [], //This array will then be filled with questions regarding each of the categories
'children_categories' => [
'Algebra' => [
'category_id' => 2,
'questions' => [],
'children_categories' => [
'Expanding brackets' => [
'category_id' => 3,
'questions' => [],
'children_categories' => []
],
'Factorising brackets' => [
'category_id' => 4,
'questions' => [],
'children_categories' => []
]
]
]
]
],
'English' => [
'category_id' => 5,
'questions' => [],
'children_categories' => [
'Shakespeare' => [
'category_id' => 6,
'questions' => [],
'children_categories' => []
]
]
]
]
So far I've been able to format categories that have no parents, but I for the life of me cannot figure out how to insert a category that has a parent into that parent's children_categories[] array. Here's the code I'm using, I need help figuring out what I should put in the "else" part of the foreach()
foreach($ids_as_keys as $category_id => $info){ //$info contains the name of the category, and the parent's ID (NULL if there is no parent)
if(is_null($info['parent_category_id'])){ //There is no parent, so put it at the root of $nested
$nested[$info['name']] = [
'category_id' => $category_id,
'questions' => [],
'children_categories' => []
];
}else{ //There is a parent, so search through all items (including sub-arrays, sub-sub-arrays etc.) until we find a match for the parent_category_id, and then add it into the children_categories[] array
}
}
return $nested;
I tested this, absolutely works :
$arr = array(
1 => array(
'name' => 'Maths',
'parent_category_id' => NULL
),
2 => array(
'name' => 'Algebra',
'parent_category_id' => 1
),
3 => array(
'name' => 'Expanding brackets',
'parent_category_id' => 2
),
4 => array(
'name' => 'Factorising brackets',
'parent_category_id' => 2
),
5 => array(
'name' => 'English',
'parent_category_id' => NULL
),
6 => array(
'name' => 'Shakespeare',
'parent_category_id' => 5
)
);
foreach ($arr as $key => &$value) {
if ($value['parent_category_id']) {
$arr[$value['parent_category_id']]['children_categories'][] = &$value;
}
else{
$parents[]=$key;
}
}
$result = array();
foreach ($parents as $val) {
$result[$val] = $arr[$val];
}
print_r($result);
This answer is too close may helpful for you
<?php
$array = [
1 => [
'name' => 'Maths',
'parent_category_id' => NULL
],
2 => [
'name' => 'Algebra',
'parent_category_id' => 1
],
3 => [
'name' => 'Expanding brackets',
'parent_category_id' => 2
],
4 => [
'name' => 'Factorising brackets',
'parent_category_id' => 2
],
5 => [
'name' => 'English',
'parent_category_id' => NULL
],
6 => [
'name' => 'Shakespeare',
'parent_category_id' => 5
]
];
//data array
$data = array();
$i = 0;
//gothrough one by one
foreach($array as $key=>$value)
{
//set the parent array
if(is_null($value['parent_category_id']))
{
$data[$value['name']]= array();
$data[$value['name']]['category_id'] = $key;
$data[$value['name']]['questions'] = array();
$data[$value['name']]['children_categories'] = array();
//add the childrens according to the parent
}elseif(array_key_exists($value['parent_category_id'], $array)){
//find the parent
$parent = $array[$value['parent_category_id']];
$data[$parent['name']]['children_categories'][$value['name']] = array();
$data[$parent['name']]['children_categories'][$value['name']]['category_id'] = $key;
$data[$parent['name']]['children_categories'][$value['name']]['questions'] = array();
}
}
//display the result
print_r($data);
Try using recursive function.
function insert_child($curArr,$childArray,&$parentArray){
foreach($parentArray as $key=>&$val){
if(is_array($val) && sizeof($val) > 0 ){
if($val['category_id']==$curArr['parent_category_id']){
$val['children_categories'][$curArr['name']] = $childArray;
return TRUE;
}else{
insert_child($curArr,$childArray,$val['children_categories']);
}
}
}
return FALSE;
}
Where $nest is your input array
$nest = array(
1=>array(
'name' => 'Maths',
'parent_category_id' => NULL
),
2=>array(
'name' => 'Algebra',
'parent_category_id' => 1
),
3=>array(
'name' => 'Expanding brackets',
'parent_category_id' => 2
),
4=>array(
'name' => 'Factorising brackets',
'parent_category_id' => 2
),
5=>array(
'name' => 'English',
'parent_category_id' => NULL
),
6=>array(
'name' => 'Shakespeare',
'parent_category_id' => 5
),
);
code
$result=array();
foreach($nest as $key=>$val){
$temp = array(
'category_id'=>$key,
'questions'=>array(),
'children_categories'=>array(),
);
if(!in_array($val['name'],$result) && $val['parent_category_id']==NULL){
$result[$val['name']] = $temp;
}else{
insert_child($val,$temp,$result);
}
}
echo "<pre>";
print_r($result);
exit();
PHPFIddle here