PHP Reorder array to reflect parent / id hierarchy - php

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'];
}
}

Related

Sort all child by parent id

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"];
});

How To Merge/push array into one in php

code
$result = [];
foreach ($getAllAgent as $rkey => $rvalue) {
$found = -1;
for ($i = 0; $i < count($result); $i++) {
if ($result[$i]["brokerid"] == $rvalue["brokerid"]) {
$found = $i;
$result[$i]['get_agent_details'][] = $rvalue['get_agent_details']; //here to combine
break;
}
}
// if not found, create new
if ($found == -1) {
$result[] = $rvalue;
}
results
Array
(
[0] => Array
(
[id] => 2
[brokerid] => 2
[agentid] => 3
[addedby] => 1
[get_agent_details] => Array
(
[id] => 3
[name] => kenang
[ic] => 932132923
[phone] => 2313123
[0] => Array
(
[id] => 4
[name] => ivan
[ic] => 32992131
[phone] => 31231
)
)
)
)
I have one set of an array, and I loop it and restructure match the data based on ID. After that I will try to merge the same data into one array, I able add into one array. But it will not combine as one. The correct result should be as below.
[get_agent_details] => Array
(
[0] => Array(
[id] => 3
[name] => kenang
[ic] => 932132923
[phone] => 2313123
),
[1] => Array
(
[id] => 4
[name] => ivan
[ic] => 32992131
[phone] => 31231
)
)
Your problem is in this line:
$result[] = $rvalue;
Consider the case where you only have one item; this will result in:
Array
(
[0] => Array
(
[id] => 2
[brokerid] => 2
[agentid] => 3
[addedby] => 1
[get_agent_details] => Array
(
[id] => 1
[name] => Chesney Hawkes
[ic] => 932132923
[phone] => 2313123
)
)
)
But to be consistent, you need get_agent_details to be a list of items, that happens to have one entry:
Array
(
[0] => Array
(
[id] => 2
[brokerid] => 2
[agentid] => 3
[addedby] => 1
[get_agent_details] => Array
(
[0] => Array
(
[id] => 1
[name] => Chesney Hawkes
[ic] => 932132923
[phone] => 2313123
)
)
)
)
So you need to re-arrange your data, for instance by writing:
$rvalue['get_agent_details'] = [0 => $rvalue['get_agent_details']];
$result[] = $rvalue;
Then, since get_agent_details will already be a list when you encounter a second matching item, your existing code in the inner loop will do the right thing:
// Add an item to the list
$result[$i]['get_agent_details'][] = $rvalue['get_agent_details'];

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

Copying a multi dimensional array of nodes into another array

I am looking to convert a multi dimensional array into another multidimensional array using a recursive function.
Source array :
Array
(
[1] => Array
(
[id] => 1
[source_name] => kk56ca1d0f2378f
[company_id] => 1
[lft] => 1
[rgt] => 18
[parent_id] => 0
[children] => Array
(
[2] => Array
(
[id] => 2
[source_name] => kk56ca1d17f3f63
[company_id] => 1
[lft] => 2
[rgt] => 3
[parent_id] => 1
[children] => Array
(
)
)
[3] => Array
(
[id] => 3
[source_name] => kk56ca1d1ebe975
[company_id] => 1
[lft] => 4
[rgt] => 13
[parent_id] => 1
[children] => Array
(
[6] => Array
(
[id] => 6
[source_name] => kk56ca1fc882ac0
[company_id] => 1
[lft] => 5
[rgt] => 10
[parent_id] => 3
[children] => Array
(
)
)
)
)
)
)
)
which I need to get into the format of
Array
(
[0] => Array
(
[id] => 1
[text] => kk56ca1d0f2378f
[parent_id] => 0
[nodes] => Array
(
[0] => Array
(
[id] => 2
[text] => kk56ca1d17f3f63
[parent_id] => 1
[nodes] => Array
(
)
)
[1] => Array
(
[id] => 3
[text] => kk56ca1d1ebe975
[parent_id] => 1
[nodes] => Array
(
[0] => Array
(
[id] => 6
[text] => kk56ca1fc882ac0
[parent_id] => 3
[nodes] => Array
(
)
)
[1] => Array
(
[id] => 15
[text] => kk
[parent_id] => 3
[nodes] => Array
(
)
)
)
)
)
)
)
I have been trying for hours and getting nowhere with this. Any help would be really appreciated.
The source array has associative indexes (though they are numbers) and the destination array has numerical indexes. Besides this, just need to remove a few indexes and change names of a few.
EDIT :
Specific changes :
change index name source_name to text
change index name children to nodes
unset indexes lft, rgt, company_id
I do not have much experience with recursion so I have trying fruitlessly.
This is what I could come up with :
// pass array of nodes
function convert_array($from){
// this is a node
if(isset($from['source_name']))
{
$temp = array();
$temp['id'] = $from['id'];
convert_array($from['children']);
}
// this is an array of nodes
else
{
foreach($from as $arr)
{
$ret = convert_array($arr);
print_r($ret);
}
}
}
But I am not able to understand what data to be returned and how the new array builds up from the return values.
Here the working function:
function convert_array( $array )
{
$retval = array();
foreach( $array as $row )
{
$child = array();
$child['id'] = $row['id'];
$child['text'] = $row['source_name'];
$child['parent_id'] = $row['parent_id'];
if( count( $row['children'] ) )
{ $child['nodes'] = convert_array( $row['children'] ); }
else
{ $child['nodes'] = array(); }
$retval[] = $child;
}
return $retval;
}
3v4l demo
I think it is self-explanatory, BTW: we init an empty array ($retval), then we perform a foreach loop through all array argument: for each element, we init a new array and we add it id, source_name as text and parent_id; if the children index has elements, we perform a recursive call to fill nodes array index, otherwise we set it to empty array.

Order array multi-dimensional

I have an array that looks like this:
$cars = array (
array(
'a' => 'audi',
'b' => 'a4'),
array(
'a' => 'peugeot',
'b' => '306'),
array(
'a' => 'audi',
'b' => 'a4'),
array(
'a' => 'audi',
'b' => 'a5'),
array(
'a' => 'peugeot',
'b' => '106'),
array(
'a' => 'peugeot',
'b' => '106'),
);
I need to order arrays like this to (id is the same as name):
name => audi
id=> audi
data => a4 => 2
a5 => 1
name => peugeot
id=> peugeot
data => 306 => 1
106 => 2
So the car brands need to be grouped an the car types counted.
I already have this code; but that is only for the group part and the count part is missing.
function mergeAndOrder($data){
// set group arrays
$i = 0; $group1 = array();
// loop trough array
$array = array(); $array2 = array();
if($data != null){
foreach($data AS $row){
// search and order level1
$search = array_search($row->a,$group1);
// this object is not found
if(is_int($search) == false){
$group1[$i] = $row->a;
$array[$i]['id'] = $row->a;
$array[$i]['name'] = $row->a;
$array[$i]['data'] = array();
$i++;
}
}
}
return $array;
}
Does somebody know an solution for this case? Thanks!
--- INPUT (part of) ---
a = lease company in this case
Array
(
[0] => stdClass Object
(
[b] => AUDI
[a] => LPN
)
[1] => stdClass Object
(
[b] => AUDI
[a] => LPN
)
[2] => stdClass Object
(
[b] => AUDI
[a] => LPN
)
[3] => stdClass Object
(
[b] => AUDI
[a] => LPN
)
--- OUTPUT (part of) ---
Array
(
[0] => Array
(
[id] => LPN
[name] => LPN
[data] => Array
(
)
)
[1] => Array
(
[id] => ARV
[name] => ARV
[data] => Array
(
)
)
[2] => Array
(
[id] => ARVB
[name] => ARVB
[data] => Array
(
)
)
[3] => Array
(
[id] => LPD
[name] => LPD
[data] => Array
(
)
)
)
Array
(
[0] => Array
(
[id] => LPN
[name] => LPN
[data] => Array
(
)
)
[1] => Array
(
[id] => ARV
[name] => ARV
[data] => Array
(
)
)
[2] => Array
(
[id] => ARVB
[name] => ARVB
[data] => Array
(
)
)
If I understand your question correctly, this should do what you want.
function mergeAndOrder ($data) {
$output = array();
foreach ($data as $item) {
$id = $item->a;
$value = $item->b;
if (!array_key_exists($id, $output)) {
$output[$id] = array('id' => $id, 'name' => $id, 'data' => array());
}
if (!array_key_exists($value, $output[$id]['data'])) {
$output[$id]['data'][$value] = 0;
}
$output[$id]['data'][$value]++;
}
// Order by name element
uasort($output, function ($a, $b) {
return strcasecmp($a['name'], $b['name']);
});
return $output;
}
Output:
Array
(
[audi] => Array
(
[id] => audi
[name] => audi
[data] => Array
(
[a4] => 2
[a5] => 1
)
)
[peugeot] => Array
(
[id] => peugeot
[name] => peugeot
[data] => Array
(
[306] => 1
[106] => 2
)
)
)

Categories