PHP Array sorting by parent - php

I got a complex array to be sorted, it looks like this:
Array
(
[0] => Array
(
[id] => 1171409310
[parent] => 1171287657
[createdAt] => 2013-12-20T12:42:19
)
[1] => Array
(
[id] => 1171360372
[parent] => 1171313704
[createdAt] => 2013-12-20T11:18:46
)
[2] => Array
(
[id] => 1171313704
[parent] => 1171304353
[createdAt] => 2013-12-20T10:14:46
)
[3] => Array
(
[id] => 1171304353
[parent] => 1171287657
[createdAt] => 2013-12-20T09:55:34
)
[4] => Array
(
[id] => 1171303539
[parent] => 1171014482
[createdAt] => 2013-12-20T09:53:54
)
[5] => Array
(
[id] => 1171287657
[parent] => 1170597579
[createdAt] => 2013-12-20T09:29:34
)
[6] => Array
(
[id] => 1171264520
[parent] => 1169354287
[createdAt] => 2013-12-20T08:58:26
)
[7] => Array
(
[id] => 1171014482
[parent] =>
[createdAt] => 2013-12-20T02:51:24
)
[8] => Array
(
[id] => 1170700661
[parent] => 1170597579
[createdAt] => 2013-12-19T21:30:31
)
[9] => Array
(
[id] => 1170597579
[parent] =>
[createdAt] => 2013-12-19T20:22:40
)
[10] => Array
(
[id] => 1169362457
[parent] =>
[createdAt] => 2013-12-18T22:27:28
)
[11] => Array
(
[id] => 1169354287
[parent] =>
[createdAt] => 2013-12-18T22:20:08
)
[12] => Array
(
[id] => 1169315244
[parent] =>
[createdAt] => 2013-12-18T21:52:59
)
)
I want the array to be first sorted by date (oldest on the top) and then each child after its parent (oldest on the top as well). The problem is that children can also be parents who have children as well so there are multiple dimensions. If possible I want also add the dimension.
I hope that my problem is clear.
EDIT: I get the array from the disqus API and want it to be sorted like it is on a website.
EDIT: It has to end like this:
Array
(
[12] => Array
(
[id] => 1169315244
[parent] =>
[createdAt] => 2013-12-18T21:52:59
)
[11] => Array
(
[id] => 1169354287
[parent] =>
[createdAt] => 2013-12-18T22:20:08
)
[6] => Array
(
[id] => 1171264520
[parent] => 1169354287
[createdAt] => 2013-12-20T08:58:26
)
[10] => Array
(
[id] => 1169362457
[parent] =>
[createdAt] => 2013-12-18T22:27:28
)
[9] => Array
(
[id] => 1170597579
[parent] =>
[createdAt] => 2013-12-19T20:22:40
)
[8] => Array
(
[id] => 1170700661
[parent] => 1170597579
[createdAt] => 2013-12-19T21:30:31
)
[5] => Array
(
[id] => 1171287657
[parent] => 1170597579
[createdAt] => 2013-12-20T09:29:34
)
[3] => Array
(
[id] => 1171304353
[parent] => 1171287657
[createdAt] => 2013-12-20T09:55:34
)
[2] => Array
(
[id] => 1171313704
[parent] => 1171304353
[createdAt] => 2013-12-20T10:14:46
)
[1] => Array
(
[id] => 1171360372
[parent] => 1171313704
[createdAt] => 2013-12-20T11:18:46
)
[0] => Array
(
[id] => 1171409310
[parent] => 1171287657
[createdAt] => 2013-12-20T12:42:19
)
[7] => Array
(
[id] => 1171014482
[parent] =>
[createdAt] => 2013-12-20T02:51:24
)
[4] => Array
(
[id] => 1171303539
[parent] => 1171014482
[createdAt] => 2013-12-20T09:53:54
)
)

I'm building a comment system myself, currently. Just ordering the comments like this is not going to really give you a strong relationship between comments (a parent-child relationship).
In this case, I'd do the following:
$comments = array();
foreach ($results as $result) {
if ($result["parent"]) {
$result["children"] = array();
$comments[$result["id"]] = $result;
}
}
// Have yet to do this a better way. Second loop is there for a reason.
foreach ($results as $result) {
if ($result["parent"])
$comments[$result["parent"]]["children"] = $result;
}
var_dump($comments);
// you can now sort on createdAt using uasort(array $array, callable $func)
uasort($comments, function ($a, $b) {
if ($a["createdAt"] == $b["createdAt"])
return 0;
return ($a["createdAt"] > $b["createdAt"]) ? 1 : -1;
// reverse this to change sort order
});

uasort($array, function($a, $b) {
// sort by date first
if (#$a["createdAt"] == #$b["createdAt"]){
return 0;
}
return (#$a["createdAt"] > #$b["createdAt"]) ? 1 : -1;
});
$array_asc = array();
foreach($array as $key => $val){
// create an array with ids as keys and children
// with the assumption that parents are created earlier.
// store the original key
$array_asc[$val['id']] = array_merge($val, array('org_key' => $key));
if ($val['parent']){
$array_asc[$val['parent']]['children'][] = $val['id'];
}
}
$array_out = array();
// get a flat array again
foreach($array_asc as $val){
if ($val['parent']){
continue;
}
add_to_output($array_out, $val, $array_asc);
}
function add_to_output(&$array_out, $val, $array_asc){
$array_out[$val['org_key']] = $val;
if (sizeof($val['children'])){
foreach($val['children'] as $id){
add_to_output($array_out, $array_asc[$id], $array_asc);
}
}
unset($array_out[$val['org_key']]['children'], $array_out[$val['org_key']]['org_key']);
}
not tested.

you can user the php array_multisort
you probably want to build your array like this
<?php
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);
}
?>
<?php
$data[] = array('createdAt' => 67, 'parent' => 2);
$data[] = array('createdAt' => 86, 'parent' => 1);
$data[] = array('createdAt' => 85, 'parent' => 6);
$data[] = array('createdAt' => 98, 'parent' => 2);
$data[] = array('createdAt' => 86, 'parent' => 6);
$data[] = array('createdAt' => 67, 'parent' => 7);
// Pass the array, followed by the column names and sort flags
$sorted = array_orderby($name_of_array, 'createdAt', SORT_DESC, 'parent', SORT_ASC);
?>

Related

Making a nested array in php

Probably my question is too much common or easy for you, but I really have no idea how to do it. Trying all everything I know and lots of googling didn't help me.
I just need a nested array.
Here is my PHP code:
EDITED
Corrected: $data['product_names'][$language['language_id']][] = array(
$data['product_names'] = array();
foreach ($data['languages'] as $language) {
$product_names_info = $this->model_catalog_category->getCategoryMultiLang($this->request->get['product_id'], $language['language_id']);
if ($product_names_info) {
$data['product_names'][$language['language_id']][] = array(
'category_id' => $product_names_info['category_id'],
'language_id' => $product_names_info['language_id'],
'name' => $product_names_info['name']
);
}
}
print_r($data['product_names']);
The result that I get:
Array
(
[5] => Array
(
[0] => Array
(
[category_id] =>
[language_id] =>
[name] =>
)
)
[2] => Array
(
[0] => Array
(
[category_id] =>
[language_id] =>
[name] =>
)
)
[4] => Array
(
[0] => Array
(
[category_id] =>
[language_id] =>
[name] =>
)
)
...
The result should look like this:
Array
(
[0] => Array
(
[language_id] => 1
[category_id] => 8
[name] => book
)
[1] => Array
(
[language_id] => 5
[category_id] => 188
[name] => magazine
)
...
)
Array
(
[0] => Array
(
[language_id] => 1
[category_id] => 8
[name] => buch
)
...
UPDATED
The result of print_r($product_names_info); inside foreach ($data['languages'] as $key => $language) {
Array
(
[0] => Array
(
[language_id] => 5
[category_id] => 8
[name] => Gecelik
)
[1] => Array
(
[language_id] => 5
[category_id] => 188
[name] => Sabahlık
)
...
)
Array
(
[0] => Array
(
[language_id] => 2
[category_id] => 8
[name] => لباس خواب
)
[1] => Array
(
[language_id] => 2
[category_id] => 188
[name] => Sabahlık
)
Thanks for any kind help.
$data['product_names'] = array();
foreach ($data['languages'] as $language) {
$product_names_info = $this->model_catalog_category->getCategoryMultiLang($this->request->get['product_id'], $language['language_id']);
if ($product_names_info) {
foreach ($product_names_info as $key => $value) {
$data['product_names'][$language['language_id']][] = array(
'category_id' => $value['category_id'],
'language_id' => $value['language_id'],
'name' => $value['name'],
);
}
}
}
print_r($data['product_names']);
I think you were missing foreach for the data you fetched into var $product_names_info

How to get list all multidimensional array with parent index

How to get list all multidimensional array with parent index. All index in each level is unique and i want to show all list with the level.
example my arrays:
Array(
[1] => Array(
[2] => Array(
[3] =>
[4] =>
[7] =>
)
)
[6] => Array(
[11] => Array(
[12] => Array(
[17] =>
)
)
)
[2] => Array(
[13] => Array(
[14] =>
)
)
)
I want to get output like this:
Array
(
[1]=array([level] = 1)
[2]=array([level] = 2)
[3]=array([level] = 3)
[4]=array([level] = 3)
[7]=array([level] = 3)
[6]=array([level] = 1)
[11]=array([level] = 2)
[12]=array([level] = 3)
[17]=array([level] = 4)
...
)
Here is a solution using a recursive function. Assuming your array will have a NULL value if there is no more child/nested arrays.
$arr = array(1 => array(2 => array(3 => NULL,
4 => NULL,
7 => NULL )),
6 => array(11 => array(12 => array(17 =>NULL))),
2 => array(13 => array(14 => NULL)));
$rslt_arr = array();
function traverse_arr($array, $level)
{
$level++;
foreach ($array as $key => $value){
if($value != NULL){
traverse_arr($value, $level);
}
$GLOBALS['rslt_arr'][$key]['level'] = $level;
}
}
traverse_arr($arr, 0);
echo '<pre>';
print_r($rslt_arr);
OUTPUT:
Array
(
[3] => Array
(
[level] => 3
)
[4] => Array
(
[level] => 3
)
[7] => Array
(
[level] => 3
)
[2] => Array
(
[level] => 1
)
[1] => Array
(
[level] => 1
)
[17] => Array
(
[level] => 4
)
[12] => Array
(
[level] => 3
)
[11] => Array
(
[level] => 2
)
[6] => Array
(
[level] => 1
)
[14] => Array
(
[level] => 3
)
[13] => Array
(
[level] => 2
)
)

array one format to another

I have one array in two format. I want to change array from
Array
(
[step_number] => 4
[app_id] => Array
(
[0] => 2
[1] => 3
)
[formdata] => Array
(
[0] => Array
(
[name] => app_id[]
[value] => 2
)
[1] => Array
(
[name] => app_id[]
[value] => 3
)
[2] => Array
(
[name] => fieldval[2][2][]
[value] => 1
)
[3] => Array
(
[name] => fieldval[3][3][]
[value] => 200
)
[4] => Array
(
[name] => fieldval[3][3][]
[value] => day
)
[5] => Array
(
[name] => title
[value] => new plan
)
[6] => Array
(
[name] => feature_plan
[value] => 3
)
[7] => Array
(
[name] => plan_type
[value] => free
)
[8] => Array
(
[name] => price
[value] =>
)
[9] => Array
(
[name] => sell_type
[value] => us
)
)
)
this format to
Array
(
[app_id] => Array
(
[0] => 2
[1] => 3
)
[fieldval] => Array
(
[2] => Array
(
[2] => Array
(
[0] => 1
)
)
[3] => Array
(
[3] => Array
(
[0] => 200
[1] => day
)
)
)
[title] => new plan
[feature_plan] => 3
[plan_type] => free
[price] =>
[sell_type] => us
)
these are are one array into two format. i have data in to first array format and i want to change that format to second array type format.
please tell me how i am trying this for 2 days but not succeed.
Here is a function you could use to produce that conversion:
function convert_formdata($input) {
$output = array();
foreach($input['formdata'] as $data) {
$keys = preg_split("#[\[\]]+#", $data['name']);
$value = $data['value'];
$target = &$output;
foreach($keys as $key) {
// Get index for "[]" reference
if ($key == '') $key = count($target);
// Create the key in the parent array if not there yet
if (!isset($target[$key])) $target[$key] = array();
// Move pointer one level down the hierarchy
$target = &$target[$key];
}
// Write the value at the pointer location
$target = $value;
}
return $output;
}
You would call it like this:
$output = convert_formdata($input);
See it run on eval.in for the given input. The output is:
array (
'app_id' =>
array (
0 => 2,
1 => 3,
),
'fieldval' =>
array (
2 =>
array (
2 =>
array (
0 => 1,
),
),
3 =>
array (
3 =>
array (
0 => 200,
1 => 'day',
),
),
),
'title' => 'new plan,',
'feature_plan' => 3,
'plan_type' => 'free',
'price' => NULL,
'sell_type' => 'us',
)

Recursive function for building array from tree

I have an array that looks like this:
Array (
[0] => Array
(
[term_id] => 23
[name] => testasdf
[depth] => 1
)
[1] => Array
(
[term_id] => 26
[name] => asdf
[depth] => 2
)
[2] => Array
(
[term_id] => 31
[name] => Another level deep
[depth] => 3
)
[3] => Array
(
[term_id] => 32
[name] => Another level deep
[depth] => 2
)
[4] => Array
(
[term_id] => 24
[name] => testasdf
[depth] => 1
)
[5] => Array
(
[term_id] => 27
[name] => asdf
[depth] => 1
)
)
Here is the recursive function that I'm using, it works except in some cases (where the depth is greater it seems.
function process(&$arr, &$prev_sub = null, $cur_depth = 1) {
$cur_sub = array();
while($line = current($arr)){
if($line['depth'] < $cur_depth){
return $cur_sub;
}elseif($line['depth'] > $cur_depth){
$prev_sub = $this->process($arr, $cur_sub, $cur_depth + 1 );
}else{
$cur_sub[$line['term_id']] = array('term_id' => $line['term_id'], 'name' => $line['name']);
$prev_sub =& $cur_sub[$line['term_id']];
next($arr);
}
}
return $cur_sub;
}
This is how the results look:
Array
(
[23] => Array
(
[26] => Array
(
[31] => Array
(
[term_id] => 31
[name] => Another level deep
)
)
[32] => Array
(
[term_id] => 32
[name] => Another level deep
)
)
[24] => Array
(
[term_id] => 24
[name] => testasdf
)
[27] => Array
(
[term_id] => 27
[name] => asdf
)
)
Any idea how I can have it so the term_id and name is shown for all depths?
try this:
function process(&$arr, &$prev_sub = null, $cur_depth = 1) {
$cur_sub = array();
while($line = current($arr)){
if($line['depth'] < $cur_depth){
return $cur_sub;
}
if($line['depth'] > $cur_depth){
$prev_sub = $this->process($arr, $cur_sub, $cur_depth + 1 );
}
$cur_sub[$line['term_id']] = array('term_id' => $line['term_id'], 'name' => $line['name']);
$prev_sub =& $cur_sub[$line['term_id']];
next($arr);
}
return $cur_sub;
}

Array filteration PHP

I have an array with values like:
Array
(
[0] => Array
(
[parent] => Basic
[parentId] => 1
[child] => Birthday
[childId] => 2
)
[1] => Array
(
[parent] => Basic
[parentId] => 1
[child] => Gender
[childId] => 3
)
[2] => Array
(
[parent] => Geo
[parentId] => 10
[child] => Current City
[childId] => 11
)
[3] => Array
(
[parent] => Known me
[parentId] => 5
[child] => My personality
[childId] => 7
)
[4] => Array
(
[parent] => Known me
[parentId] => 5
[child] => Best life moment
[childId] => 8
)
)
And I want to filter this array such that their filtration based on parent index, and the final result would be like:
Array
(
[0] => Array
(
[parent] => Basic
[parentId] => 1
[child] => Array
(
[0] => Birthday
[1] => Gender
)
)
[1] => Array
(
[parent] => Geo
[parentId] => 10
[child] => Array
(
[0] => Current City
)
)
[2] => Array
(
[parent] => Known me
[parentId] => 5
[child] => Array
(
[0] => My personality
[1] => Best life moment
)
)
)
For that I coded :
$filter = array();
$f = 0;
for ($i=0; $i<count($menuArray); $i++) {
$c = 0;
for( $b = 0; $b < count($filter); $b++ ){
if( $filter[$b]['parent'] == $menuArray[$i]['parent'] ){
$c++;
}
}
if ($c == 0) {
$filter[$f]['parent'] = $menuArray[$i]['parent'];
$filter[$f]['parentId'] = $menuArray[$i]['parentId'];
$filter[$f]['child'][] = $menuArray[$i]['child'];
$f++;
}
}
But it results :
Array
(
[0] => Array
(
[parent] => Basic
[parentId] => 1
[child] => Array
(
[0] => Birthday
)
)
[1] => Array
(
[parent] => Geo
[parentId] => 10
[child] => Array
(
[0] => Current City
)
)
[2] => Array
(
[parent] => Known me
[parentId] => 5
[child] => Array
(
[0] => My personality
)
)
)
Could anyone point out my missing LOC?
Try:
$filter = array();
foreach ($menuArray as $menu) {
if (!array_key_exists($menu['parent_id'], $filter)) {
$filter[$menu['parent_id']] = array(
'parent' => $menu['parent'],
'parent_id' => $menu['parent_id'],
'child' => array()
);
}
$filter[$menu['parent_id']]['child'][$menu['child_id']] = $menu['child'];
}
This will produce an array like:
Array
(
[1] => Array
(
[parent] => Basic
[parentId] => 1
[child] => Array
(
[2] => Birthday
[3] => Gender
)
)
[10] => Array
(
[parent] => Geo
[parentId] => 10
[child] => Array
(
[11] => Current City
)
)
[5] => Array
(
[parent] => Known me
[parentId] => 5
[child] => Array
(
[7] => My personality
[8] => Best life moment
)
)
)
Notice that the array indexes match the IDs. You can't loop this with a for loop but you can foreach ($filter as $parent_id=>$parent) correctly. If you want to you can change line 4 of my code to $filter['key_' . $menu['parent_id']] to force a string and a for loop will work
The next piece of code is completely untested, and based on the idea that it's sorted by parentId.
$filter = array();
$option = null;
for( $i = 0; $i < count( $menuArray ); $i++ ) {
if( count( $filter ) < 1 || $filter[count($filter)-1]['parentId'] != $menuArray['parentId'] ) {
if( $option != null ) {
$filter[] = $option;
}
$option = array(
"parent" => $menuArray[$i]['parent'],
"parentId" => $menuArray[$i]['parentId'],
"child" => array()
);
}
$option['child'][] = $menuArray[$i]['child'];
}
$filter[] = $option; // one last time, because we left the loop already.
unset( $option ); // we don't need it anymore.
What it does, it creates a $option for every parent. As soon as we hit the next parentId we add the current $option to the $filter array and create a new $option object.
All the children just keep getting added to the current $option.

Categories