Sort all child by parent id - php

i have array like this:
(
[0] => Array
(
[id] => 1
[name] => Bazowa
[parent_id] => 0
)
[1] => Array
(
[id] => 2
[name] => Główna
[parent_id] => 1
)
[2] => Array
(
[id] => 12
[name] => PlayStation
[parent_id] => 2
)
[3] => Array
(
[id] => 13
[name] => Xbox
[parent_id] => 2
)
[4] => Array
(
[id] => 14
[name] => Nintendo
[parent_id] => 2
)
[5] => Array
(
[id] => 15
[name] => PC
[parent_id] => 2
)
)
and i want sort this array like tree on screenshot below:
Screen of tree what I want
i trying use this Sort array values based on parent/child relationship
foreach($xml->children()->children() as $value) {
if($value->active == 1) {
$categories[] = [
'id' => (int) $value->id,
'name' => (string) $value->name->language,
'parent_id' => (int) $value->id_parent
];
}
}
$parent_ids = [];
$parents = ['' => []];
foreach($categories as $val) {
$parents[$val['parent_id']][] = $val;
}
$sorted = $parents[''];
dump($parents); exit;
for($val = reset($sorted); $val; $val = next($sorted)) {
if(isset($parents[$val[0]])) {
foreach($parents[$val[0]] as $next) {
$sorted[] = $next;
}
}
}
The most important thing for me is that everything displays well in select, which is something like this:
-Playstation
-- Playstation 5
--- Gry
--Playstation 3
--- Gry
Anyone can help me?
EDIT:
Problem solved by Build a tree from a flat array in PHP

This should work
usort($arr, function($a, $b) {
return $a["parent_id"] > $b["parent_id"];
});

Related

How to count specific key values from a multi-dimensional array?

I have a vendor data array listed as a tree structure and each vendor have a type.
These are types of vendor and its id:
Agency = 1
Branch Agency = 2
Wholsaler = 3
Smartshop = 4
Example: ['type']=>2 (here this vendor is a branch agency).
My question is: How can I get the count of Branch agencies are in this array, same count of wholesaler and smart shop?
Desired result:
[2 => 2, 3 => 2, 4 => 1]
Here is my dynamic generated array:
Array
(
[2] => Array
(
[id] => 2
[type] => 2
[name] => R-1 Agency
[parent] => 1
[children] => Array
(
[3] => Array
(
[id] => 3
[type] => 3
[name] => R-1-W-1
[parent] => 2
[children] => Array
(
[11] => Array
(
[id] => 11
[type] => 4
[name] => mdf,lk
[parent] => 3
[children] => Array
(
)
)
)
)
)
)
[38] => Array
(
[id] => 38
[type] => 2
[name] => sndflk
[parent] => 1
[children] => Array
(
[40] => Array
(
[id] => 40
[type] => 3
[name] => new one
[parent] => 38
[children] => Array
(
)
)
)
)
)
I used this function :
function take_types($array){
foreach ($array as $key => $value) {
$types[] = $value['type'];
if(!empty($value['children'])){
$this->take_types($value['children']);
}
}
return $types;
}
When I use the above function the output is like this:
Array
(
[0] => 2
[1] => 2
)
I only get two values, I need to get the count of each vendor type.
There will be many techniques to recursively process your tree data. I'll offer a native function style and a custom recursive style.
array_walk_recursive() visits all of the "leaf nodes", so you only need to check the key and push the value into a variable which can be accessed outside of that function's scope -- this is why "modifying by reference" is vital.
Code: (Demo)
// I removed the chunky $tree declaration from my post, see the demo
$result = [];
array_walk_recursive(
$tree,
function($v, $k) use (&$result) {
if ($k === 'type') {
$result[] = $v;
}
}
);
var_export(array_count_values($result));
Or
function recursiveTypeCount($array, $output = []) {
foreach($array as $item) {
if (!isset($output[$item['type']])) {
$output[$item['type']] = 1;
} else {
++$output[$item['type']];
}
if ($item['children']) {
$output = recursiveTypeCount($item['children'], $output);
}
}
return $output;
}
var_export(recursiveTypeCount($tree));
Both will display:
array (
2 => 2,
3 => 2,
4 => 1,
)

Combine Arrays into One Multidimensional Array using PHP

I am trying to combine arrays into one single multidimensional array. There could be more than 5 arrays that needs to be combined so I need a code that will automatically combine all arrays no matter how many they are. I tried array_merge but it requires manual defining of arrays in comma formatted parameters.
The code to convert is:
Array
(
[id] => 1
[name] => Item 1
[slug] => item-slug-1
[parent] => 0
)
Array
(
[id] => 2
[name] => Item 2
[slug] => item-slug-2
[parent] => 1
)
Array
(
[id] => 3
[name] => Item 3
[slug] => item-slug-3
[parent] => 2
)
Array
(
[id] => 4
[name] => Item 4
[slug] => item-slug-4
[parent] => 3
)
Array
(
[id] => 5
[name] => Item 5
[slug] => item-slug-5
[parent] => 3
)
And this is how I would like it to look:
Array
(
[0] => Array
{
[id] => 1
[name] => Item 1
[slug] => item-slug-1
[parent] => 0
}
[1] => Array
{
[id] => 2
[name] => Item 2
[slug] => item-slug-2
[parent] => 1
}
[2] => Array
{
[id] => 3
[name] => Item 3
[slug] => item-slug-3
[parent] => 2
}
[3] => Array
{
[id] => 4
[name] => Item 4
[slug] => item-slug-4
[parent] => 3
}
[4] => Array
{
[id] => 5
[name] => Item 5
[slug] => item-slug-5
[parent] => 3
}
)
Here is how the arrays are generated:
I receive a response JSON from the server that looks like this:
[{"slug":"item-slug-1","name":"Item 1","id":1},{"slug":"item-slug-2","name":"Item 2","id":2},{"slug":"item-slug-3","name":"Item 3","id":3,"children":[{"slug":"item-slug-4","name":"Item 4","id":4},{slug":"item-slug-5","name":"Item 5","id":5}]}]
I decode the JSON then convert it to an array like this:
$categories_obj = json_decode( $_POST['order'] );
$categories_arr = json_decode(json_encode( $categories_obj ), true);
I created a function that walks through each item so it would be easier to insert into my database:
function walk_and_update($data, $parent = 0, $count = 0) {
if( is_array($data) ) {
$combine = array();
/* The arrays are generated here */
foreach( $data as $key => $row ) {
$formatted = array(
'id' => $row['id'],
'name' => $row['name'],
'slug' => $row['slug'],
'parent' => $parent
);
print_r( $formatted );
/* My SQL update is here */
if( isset( $row['children'] ) ) {
walk_and_update( $row['children'], $row['id'], $count );
}
}
}
}
Then I use the function like this:
walk_and_update( $categories_arr );
Like this:
$arr1 = Array(
'id' => 1,
'name' => 'Item 1',
'slug' => 'item-slug-1',
'parent' => 0);
$arr2 = Array(
'id' => 2,
'name' => 'Item 2',
'slug' => 'item-slug-2',
'parent' => 1);
$arr3 = Array(
'id' => 3,
'name' => 'Item 3',
'slug' => 'item-slug-3',
'parent' => 2);
$new_arr = array();
for($i=1;$i<=3;$i++) {
$var_name = 'arr'.$i;
array_push($new_arr,$$var_name);
}
echo "<pre>";print_r($new_arr);
Output:
Array
(
[0] => Array
(
[id] => 1
[name] => Item 1
[slug] => item-slug-1
[parent] => 0
)
[1] => Array
(
[id] => 2
[name] => Item 2
[slug] => item-slug-2
[parent] => 1
)
[2] => Array
(
[id] => 3
[name] => Item 3
[slug] => item-slug-3
[parent] => 2
)
)
you could make function to handle the array, then return expected array to multidimensional array.
can i know first, that the array you want to merging , did they produce one by one or just one time that can produce many array ?
//you could do this if your array produces one time only
$counter = 0;
$new_array=array();
foreach (your array as $key => $val)
{
$new_array[$counter]['id']= $val['id'];
$new_array[$counter]['name']= $val['name'];
$new_array[$counter]['slug']= $val['slug'];
$new_array[$counter]['parent'] = $val['parent'];
$counter++;
}
//if your array produces more than one time
function main ()
{
$data['counter']=0;
$data['newarray']=array();
$data = $this->mergin_array(your array,$data['counter'])
}
function merging_array(your array,$counter)
{
$data = array();
$counter_new = $counter;
foreach(your array as $key => $val)
{
$data['newarray'][$counter]['id'] = $val['id'];
$data['newarray'][$counter]['name'] = $val['name'];
$data['newarray'][$counter]['slug'] = $val['slug'];
$data['newarray'][$counter]['parent'] = $val['parent'];
$counter_new++;
}
$data['counter'] = $counter_new;
return $data;
}
so no matter how many you use , when you access the $data['newarray'] in your main function it will get you the combined for many array

Re-structure array based on parent/child relationship

I have the following array structure:
Array
(
[0] => Array
(
[id] => 83
[parent_id] => 0
[title] => Questionnaire one
)
[1] => Array
(
[id] => 84
[parent_id] => 0
[title] => Questionnaire two
)
[2] => Array
(
[id] => 85
[parent_id] => 83
[title] => Questionnaire three
)
)
I want to re-structure the array so child items are listed under their parents. For example:
Array
(
[0] => Array
(
[id] => 83
[parent_id] => 0
[title] => Questionnaire one
)
[1] => Array
(
[id] => 85
[parent_id] => 83
[title] => Questionnaire three
)
[2] => Array
(
[id] => 84
[parent_id] => 0
[title] => Questionnaire two
)
)
I've searched previous questions but found none of them actually achieve the above.
Can someone please help me with this?
Thanks
You can try
$array = Array(
"0" => Array("id" => 83,"parent_id" => 0,"title" => "Questionnaire one"),
"1" => Array("id" => 84,"parent_id" => 0,"title" => "Questionnaire two"),
"2" => Array("id" => 85,"parent_id" => 83,"title" => "Questionnaire three"));
$id = array_map(function ($item) {return $item["id"];}, $array);
$parent = array_filter($array, function ($item){return $item['parent_id'] == 0;});
$lists = array();
foreach ($parent as $value)
{
$lists[] = $value ;
$children = array_filter($array, function ($item) use($value) {return $item['parent_id'] == $value['id'];});
foreach($children as $kids)
{
$lists[] = $kids ;
}
}
echo "<pre>";
print_r($lists);
Output
Array
(
[0] => Array
(
[id] => 83
[parent_id] => 0
[title] => Questionnaire one
)
[1] => Array
(
[id] => 85
[parent_id] => 83
[title] => Questionnaire three
)
[2] => Array
(
[id] => 84
[parent_id] => 0
[title] => Questionnaire two
)
)
You could use uksort(). Heres a DEMO.
function cmp($a, $b) {
if ($stock[$a] != $stock[$b]) return $stock[$b] - $stock[$a];
return strcmp($a, $b);
}
$a = array(5 => 'apple', 1 => 'banana', 6 => 'orange', 2 => 'kiwi');
uksort($a, "cmp");
foreach ($a as $key => $value) {
echo "$key: $value\n";
}

PHP Reorder array to reflect parent / id hierarchy

How do I rearrange the following array
[0] => Array
(
[id] => 1
[parent_id] => 0
[name] => Accueil
)
[1] => Array
(
[id] => 2
[parent_id] => 0
[name] => Exposants
)
[2] => Array
(
[id] => 3
[parent_id] => 0
[name] => Visiteurs
)
[3] => Array
(
[id] => 4
[parent_id] => 0
[name] => Medias
)
[4] => Array
(
[id] => 5
[parent_id] => 0
[name] => Activités
)
[5] => Array
(
[id] => 6
[parent_id] => 1
[name] => Contact
)
[6] => Array
(
[id] => 7
[parent_id] => 3
[name] => Partenaires
)
[7] => Array
(
[id] => 8
[parent_id] => 2
[name] => News
)
So I come up with an array that reflects the hierarchy as shown by the id and parent_id fields? The array key is the ID field of array elements are parents. Inside this array is each time a child array that has its ID field as the key. Sample:
[1] => Array
(
[name] => Accueil
[children] => array(
[0] => bla,
[3] => bla2
)
)
[2] => Array
(
[name] => Something
[children] => array(
[4] => bla3,
)
)
Works for any depth and allows children to precede parents:
<?php
$p = array(0 => array());
foreach($nodes as $n)
{
$pid = $n['parent_id'];
$id = $n['id'];
if (!isset($p[$pid]))
$p[$pid] = array('child' => array());
if (isset($p[$id]))
$child = &$p[$id]['child'];
else
$child = array();
$p[$id] = $n;
$p[$id]['child'] = &$child;
unset($p[$id]['parent_id']);
unset($child);
$p[$pid]['child'][] = &$p[$id];
}
$nodes = $p['0']['child'];
unset($p);
?>
Use var_dump on the $nodes result to see the structure. It is close to what you suggested. The major difference is that the keys are not the ids.
You could make this more DRY, but it's a quick and dirty way to handle it. Also, you could remove 6 lines if you could guarantee that each child record has a valid parent record and that the valid parent record precedes the child record in the original array.
$sorted = array();
foreach( $orig_ary as $item ) {
if ( $item['parent_id'] === 0 ) {
if ( !array_key_exists( $item['id'], $sorted ) ) {
$sorted[ $item['id'] ] = array(
'name' => '',
'children' => array()
);
}
$sorted[ $item['id'] ]['name'] = $item['name'];
} else {
if ( !array_key_exists( $item['parent_id'], $sorted ) ) {
$sorted[ $item['parent_id'] ] = array(
'name' => '',
'children' => array()
);
}
$sorted[ $item['parent_id'] ]['children'][ $item['id'] ] = $item['name'];
}
}

PHP: Recursive array function

I want to create a function that returns the full path from a set node, back to the root value. I tried to make a recursive function, but ran out of luck totally. What would be an appropriate way to do this? I assume that a recursive function is the only way?
Here's the array:
Array
(
[0] => Array
(
[id] => 1
[name] => Root category
[_parent] =>
)
[1] => Array
(
[id] => 2
[name] => Category 2
[_parent] => 1
)
[2] => Array
(
[id] => 3
[name] => Category 3
[_parent] => 1
)
[3] => Array
(
[id] => 4
[name] => Category 4
[_parent] => 3
)
)
The result I want my function to output when getting full path of node id#4:
Array
(
[0] => Array
(
[id] => 1
[name] => Root category
[_parent] =>
)
[1] => Array
(
[id] => 3
[name] => Category 3
[_parent] => 1
)
[2] => Array
(
[id] => 4
[name] => Category 4
[_parent] => 3
)
)
The notoriously bad example of my recursive skills:
function recursive ($id, $array) {
$innerarray = array();
foreach ($array as $k => $v) {
if ($v['id'] === $id) {
if ($v['_parent'] !== '') {
$innerarray[] = $v;
recursive($v['id'], $array);
}
}
}
return $innerarray;
}
assuming "id" in your sub array is that sub arrays index + 1 inside the parent array (otherwise you would need to do a search in the array each time), you could do this:
$searchNode = 4;
while ($searchNode)
{
$result[] = $nodes[$searchNode - 1];
$searchNode = $nodes[$searchNode - 1]["id"];
}
$result = array_reverse($result);

Categories