I have the array of persons:
array(
array(
'name' => 'John',
'id' => 1,
'mother_id' => 2,
'father_id' => 3
),
array(
'name' => 'Lucy',
'id' => 2,
'mother_id' => 5,
'father_id' => 4
),
array(
'name' => 'Jim',
'id' => 3,
'mother_id' => 7,
'father_id' => 9
),
array(
'name' => 'Paul',
'id' => 4,
'mother_id' => 534,
'father_id' => 54
),
array(
'name' => 'Laura',
'id' => 5,
'mother_id' => 554,
'father_id' => 51
),
array(
'name' => 'Vanessa',
'id' => 7,
'mother_id' => 5354,
'father_id' => 514
),
array(
'name' => 'Adam',
'id' => 9,
'mother_id' => 245354,
'father_id' => 514234
),
);
And I want to get this:
array(
array(
'person' => array(
'name' => 'John',
'id' => 1,
'mother_id' => 2,
'father_id' => 3
),
'parents' => array(
'mother' => array(
'person' => array(
'name' => 'Lucy',
'id' => 2,
'mother_id' => 5,
'father_id' => 4
),
'parents' => array(
'mother' => array(
'person' => array(
'name' => 'Laura',
'id' => 5,
'mother_id' => 554,
'father_id' => 51
),
'parents' => array(...)
),
'father' => array(
'person' => array(
'name' => 'Paul',
'id' => 4,
'mother_id' => 534,
'father_id' => 54
),
'parents' => array(...)
),
)
),
'father' => ...
)
So John is a child that has mother and father, father has mother and father, mother has mother and father and etc, and write a script that do something but not what I want exactly
function parseTree(& $tree, $root = null) {
$return = null;
foreach ($tree as $key=> $item){
if ($item['id'] == $root){
$return = [
'person' => $item,
'parents' => [
'father' => parseTree($tree, $item['father_id'])
]
];
unset ($tree[$key]);
}elseif($item['id'] == $root){
$return = [
'person' => $item,
'parents' => [
'father' => parseTree($tree, $item['mother_id'])
]
];
unset ($tree[$key]);
}
elseif ($root == null) {
$return = [
'person' => $item,
'parents' => [
'father' => parseTree($tree, $item['father_id']),
'mother' => parseTree($tree, $item['mother_id'])
]
];
unset ($tree[$key]);
}
}
return $return;
}
How can I make it work? Or maybe there are some proper libraries for that?
You almost had it. I would do it in this manner:
function parseTree(&$tree, $root = null)
{
$return = null;
foreach ($tree as $key => $item) {
if ($root == null || $item['id'] == $root) {
$return = [
'person' => $item,
'parents' => [
'father' => parseTree($tree, $item['father_id']),
'mother' => parseTree($tree, $item['mother_id'])
]
];
unset ($tree[$key]);
}
}
return $return;
}
Related
Here is my array:
$list = array(
array('id' => 3, 'name' => 'Phones', 'parent_id' => 0,),
array('id' => 256, 'name' => 'Accessories', 'parent_id' => 0,),
array('id' => 308, 'name' => 'Appliances', 'parent_id' => 0,),
array('id' => 1057, 'name' => 'Smart', 'parent_id' => 0,),
array('id' => 1065, 'name' => 'Smart Phones', 'parent_id' => 3,),
array('id' => 1066, 'name' => 'Feature Phones', 'parent_id' => 3,),
array('id' => 1069, 'name' => 'Samsung', 'parent_id' => 1065,),
array('id' => 1070, 'name' => 'Apple', 'parent_id' => 1065,),
array('id' => 1072, 'name' => 'Apple', 'parent_id' => 1066,),
array('id' => 1075, 'name' => 'Tablets', 'parent_id' => 0,),
array('id' => 1076, 'name' => 'Samsung', 'parent_id' => 1066,),
array('id' => 1077, 'name' => 'All Brands', 'parent_id' => 1075,),
array('id' => 1078, 'name' => 'Samsung', 'parent_id' => 1077,),
array('id' => 1079, 'name' => 'Protector', 'parent_id' => 256,),
array('id' => 1080, 'name' => 'Power', 'parent_id' => 256,),
array('id' => 1081, 'name' => 'Cable', 'parent_id' => 256,),
array('id' => 1082, 'name' => 'Memory', 'parent_id' => 256,),
);
This is the code I categorized:
function quote_make_tree($list,$deep=1, $root = 0)
{
$tree = $packData = [];
foreach ($list as $row) {
$packData[$row['id']] = $row;
}
foreach ($packData as $key => $val) {
if ($val['parent_id'] == $root) {
$tree[] = &$packData[$key];
} else {
$packData[$val['parent_id']]['children'][] = &$packData[$key];
}
}
return $tree;
}
I want to add a deep parameter $deep to quote_make_tree to control the depth of classification.
The result I want:
If $deep = 1 Get only data with parent_id = 0:
$one = array(
0 => array('id' => 3, 'name' => 'Phones', 'parent_id' => 0,),
1 => array('id' => 256, 'name' => 'Accessories', 'parent_id' => 0,),
2 => array('id' => 308, 'name' => 'Appliances', 'parent_id' => 0,),
3 => array('id' => 1057, 'name' => 'Smart', 'parent_id' => 0,),
4 => array('id' => 1075, 'name' => 'Tablets', 'parent_id' => 0,),
);
If $deep = 2,Get level 2 classification below level 1 classification,if $deep=3,Get all 1,2,3 classifications
I have tried get all the data first, then delete the data according to $deep.here is demo,thanks folks
This might be easier to solve using a recursive method. This allows you to check the depth and if you want more details then it will call itself to add in more layers. Each time calling itself you just take one off the depth...
function quote_make_tree($list, $deep=1, $root = 0) {
$output = [];
foreach ( $list as $listItem ) {
if ( $listItem['parent_id'] == $root ) {
if ( $deep > 1 ) {
$listItem['children'] = quote_make_tree($list, $deep-1, $listItem['id']);
}
$output[] = $listItem;
}
}
return $output;
}
Hello good morning wherever you are :D, i have a lil problem, i have this code of arrays
$arrayToView is the info of every single user that i want.
$tagsArray are only tags that use every user but i need to merge all the info something like the last array...
$arrayToView = array(
'IVOFACUNDO' = array(
'mails' => 3,
'contacts' => 34,
'blocked' => 23
),
'ESRAYCU' = array(
'mails' => 23,
'contacts' => 124,
'blocked' => 44
)
)
And i have another one like this
$tagsArray= array(
'IVOFACUNDO' = array(
'14' => array(
'id' => 14,
'name' => 'php',
'value' => 1
),
'15' => array(
'id' => 15,
'name' => 'javascript',
'value' => 1
)
),
'ESRAYCU' = array(
'1' => array(
'id' => 1,
'name' => 'python',
'value' => 1
),
'15'=> array(
'id' => 15,
'name' => 'javascript',
'value' => 1
)
)
)
so the question is how i can merge both arrays obviously respectively with the same admin something like this
$arrayToView = array(
'IVOFACUNDO' = array(
'mails' => 3,
'contacts' => 34,
'blocked' => 23,
'tags' => array(
'14' => array(
'id' => 14,
'name' => 'php',
'value' => 1
),
'15' => array(
'id' => 15,
'name' => 'javascript',
'value' => 1
)
)
),
'ESRAYCU' = array(
'mails' => 23,
'contacts' => 124,
'blocked' => 44,
'tags' => array(
'1' => array(
'id' => 1,
'name' => 'python',
'value' => 1
),
'15'=> array(
'id' => 15,
'name' => 'javascript',
'value' => 1
)
)
)
)
The key 'tags' need to be created in the merge of every iteration to add and get one array with all the values, how i can do this?
You can try this snippet.
foreach($arrayToView as $key => $arr){
if(array_key_exists($key, $tagsArray)){
$arrayToView[$key]['tags'] = $tagsArray[$key];
}
}
echo '<pre>';print_r($arrayToView);echo '</pre>';
Use php inbuilt function
$result_Arr = array_merge_recursive($arrayToView,$tagsArray);
<?php
$arrayToView = array(
'IVOFACUNDO' => array(
'mails' => 3,
'contacts' => 34,
'blocked' => 23
),
'ESRAYCU' => array(
'mails' => 23,
'contacts' => 124,
'blocked' => 44
)
);
$tagsArray= array(
'IVOFACUNDO' => array(
'14' => array(
'id' => 14,
'name' => 'php',
'value' => 1
),
'15' => array(
'id' => 15,
'name' => 'javascript',
'value' => 1
)
),
'ESRAYCU' => array(
'1' => array(
'id' => 1,
'name' => 'python',
'value' => 1
),
'15'=> array(
'id' => 15,
'name' => 'javascript',
'value' => 1
)
)
);
foreach($arrayToView as $key => $value){
if(isset($tagsArray[$key])){
$arrayToView[$key]['tags'] = array();
foreach($tagsArray[$key] as $key2 => $value2){
$arrayToView[$key]['tags'][$key2] = $tagsArray[$key][$key2];
}
}
}
echo'<pre>';
print_r($arrayToView);
echo'</pre>';
?>
I have a stored unlimited nested levels array with unwanted extra data.
$arr = array(
array(
'name' => 'item1',
'level' => 0,
'extra_key' => 'some_data',
'children' => array(
'name' => 'sub-item1',
'level' => 1,
'extra_key' => 'some_data',
'children' => array(
'name' => 'sub-sub-item1',
'level' => 2,
'extra_key' => 'some_data',
'children' => array()
),
array(
'name' => 'sub-sub2-item1',
'level' => 2,
'extra_key' => 'some_data',
'children' => array()
),
)
),
array(
'name' => 'item2',
'level' => 0,
'extra_key' => 'some_data',
'children' => array(
'name' => 'sub-item2',
'level' => 2,
'extra_key' => 'some_data',
'children' => array(
'name' => 'sub-sub-item2',
'level' => 2,
'extra_key' => 'some_data',
'children' => array()
),
array(
'name' => 'sub-sub2-item2',
'level' => 2,
'extra_key' => 'some_data',
'children' => array()
),
)
),
array(
'name' => 'item3',
'level' => 0,
'extra_key' => 'some_data',
'children' => array(
'name' => 'sub-item3',
'level' => 1,
'extra_key' => 'some_data',
'children' => array(
'name' => 'sub-sub-item3',
'level' => 2,
'extra_key' => 'some_data',
'children' => array()
),
array(
'name' => 'sub-sub2-item3',
'level' => 2,
'extra_key' => 'some_data',
'children' => array()
),
)
),
);
Expected output array:
$arr = array(
array(
'name' => 'item1',
'nodes' => array(
'name' => 'sub-item1',
'nodes' => array(
'name' => 'sub-sub-item1',
'nodes' => array()
),
array(
'name' => 'sub-sub2-item1',
'nodes' => array()
),
)
),
array(
'name' => 'item2',
'nodes' => array(
'name' => 'sub-item2',
'nodes' => array(
'name' => 'sub-sub-item2',
'nodes' => array()
),
array(
'name' => 'sub-sub2-item2',
'nodes' => array()
),
)
),
array(
'name' => 'item3',
'nodes' => array(
'name' => 'sub-item3',
'nodes' => array(
'name' => 'sub-sub-item3',
'nodes' => array()
),
array(
'name' => 'sub-sub2-item3',
'nodes' => array()
),
)
)
);
I want to remove unwanted keys like level , extra_key from all levels and i want also to change the name of the key children to nodes then reproduce the same array with the same structure with the new format.
How can i achieve that?
I tried to do it by recursive function but i failed to reproduce the same structrue
Your structure doesn't make sense, probably because of that you was unable to write recursive function. If it is possible to change structure, I would suggest this one (with reformat function implementation):
<?php
$actual = array(
array(
'name' => 'item1',
'level' => 0,
'extra_key' => 'some_data',
'children' => array(
array(
'name' => 'sub-item1',
'level' => 1,
'extra_key' => 'some_data',
'children' => array(
array(
'name' => 'sub-sub-item1',
'level' => 2,
'extra_key' => 'some_data',
'children' => array()
),
array(
'name' => 'sub-sub2-item1',
'level' => 2,
'extra_key' => 'some_data',
'children' => array()
),
)
),
)
),
);
$expected = array(
array(
'name' => 'item1',
'nodes' => array(
array(
'name' => 'sub-item1',
'nodes' => array(
array(
'name' => 'sub-sub-item1',
'nodes' => array()
),
array(
'name' => 'sub-sub2-item1',
'nodes' => array()
),
),
),
)
),
);
function change_array($original)
{
return array_map('change_node', $original);
}
function change_node($node)
{
return [
'name' => $node['name'],
'nodes' => array_map('change_node', $node['children']),
];
}
var_dump($expected === change_array($actual));
This function will do what you want recursively.
You can add extra excluded and/or renamed indices if required;
function parseArray($array): array
{
// The resulting array
$result = [];
// Indices you want renamed [`from` => `to`]
$renameIndices = ['children' => 'nodes'];
// Indices you want excluded [`1`, `2`]
$excludedIndices = ['level', 'extra_key'];
foreach ($array as $idx => $content)
{
// If excluded, continue (skip) node.
if (in_array($idx, $excludedIndices, true))
{
continue;
}
// Setting the resulting (new) index.
$resultIdx = $idx;
// Check if this index should be renamed
if (array_key_exists($idx, $renameIndices))
{
// If index should be renamed, apply new name
$resultIdx = $renameIndices[$idx];
}
// If this content block is an array. Parse it.
if (is_array($content))
{
$content = parseArray($content);
}
// Save content to resulting array.
$result[$resultIdx] = $content;
}
return $result;
}
Hi I'm have recursion function that makes binary tree array, so from that
array(
array(
'name' => 'John',
'id' => 1,
'mother_id' => 2,
'father_id' => 3
),
array(
'name' => 'Lucy',
'id' => 2,
'mother_id' => 5,
'father_id' => 4
),
array(
'name' => 'Jim',
'id' => 3,
'mother_id' => 7,
'father_id' => 9
),
array(
'name' => 'Paul',
'id' => 4,
'mother_id' => 534,
'father_id' => 54
),
array(
'name' => 'Laura',
'id' => 5,
'mother_id' => 554,
'father_id' => 51
),
array(
'name' => 'Vanessa',
'id' => 7,
'mother_id' => 5354,
'father_id' => 514
),
array(
'name' => 'Adam',
'id' => 9,
'mother_id' => 245354,
'father_id' => 514234
),
);
I'm getting that:
array(
array(
'person' => array(
'name' => 'John',
'id' => 1,
'mother_id' => 2,
'father_id' => 3
),
'parents' => array(
'mother' => array(
'person' => array(
'name' => 'Lucy',
'id' => 2,
'mother_id' => 5,
'father_id' => 4
),
'parents' => array(
'mother' => array(
'person' => array(
'name' => 'Laura',
'id' => 5,
'mother_id' => 554,
'father_id' => 51
),
'parents' => array(...)
),
'father' => array(
'person' => array(
'name' => 'Paul',
'id' => 4,
'mother_id' => 534,
'father_id' => 54
),
'parents' => array(...)
),
)
),
'father' => ...
)
and it works completely fine until it gets array with more than -+100 values, and when it gets this array, it returns 500 error, that's seems strange for me, cos obviously I don't have infinite loop or something like that, cos smallest arrays parses fine but I can't figure out what's reason for this kind of behavior.
function parseTree(&$tree, $root = null)
{
$return = null;
foreach ($tree as $key => $item) {
if ($root == null || $item['id'] == $root) {
$return = [
'person' => $item,
'parents' => [
'father' => parseTree($tree, $item['father_id']),
'mother' => parseTree($tree, $item['mother_id'])
]
];
unset ($tree[$key]);
}
}
return $return;
}
How can I sort an associative array by a weight AND type?
Input
array(
'a' => array( 'type' => 't1', 'weight' => 1, 'text' => 'text1' ),
'b' => array( 'type' => 't1', 'weight' => 3, 'text' => 'text2' ),
'c' => array( 'type' => 't2', 'weight' => 5, 'text' => 'text3' ),
'd' => array( 'type' => 't1', 'weight' => 2, 'text' => 'text4' ),
'e' => array( 'type' => 't2', 'weight' => 4, 'text' => 'text5' ),
'f' => array( 'type' => 't2', 'weight' => 4, 'text' => 'text6' )
);
Desired Output
array(
'a' => array( 'type' => 't1', 'weight' => 1, 'text' => 'text1' ),
'd' => array( 'type' => 't1', 'weight' => 2, 'text' => 'text4' ),
'b' => array( 'type' => 't1', 'weight' => 3, 'text' => 'text2' ),
'e' => array( 'type' => 't2', 'weight' => 1, 'text' => 'text5' ),
'f' => array( 'type' => 't2', 'weight' => 1, 'text' => 'text6' ),
'c' => array( 'type' => 't2', 'weight' => 5, 'text' => 'text3' )
);
Type "t2" must appear at end of array, all other types at start.
Weight must be sorted after type.
I am using uasort with a custom compare function, but am struggling. Here is what I have, but it doesn't work:
function my_comparer($a, $b) {
return ( $a['type'] !== 't2' && $b['type'] === 't2' )
? -1
: $a['weight'] - $b['weight'];
}
Your function doesn't take account of ($a['type']=='t2')
function my_comparer($a, $b) {
if ( ($a['type']==='t2') && ($b['type']!=='t2')) return -1;
if ( ($b['type']==='t2') && ($a['type']!=='t2')) return 1;
return ($a['weight'] - $b['weight']);
}
Try this:
function my_comparer($a, $b) {
if( $a['type'] == $b['type'] ){
return $a['weight'] - $b['weight'];
}else{
if( $a['type'] > $b['type'] ) return 1;
else return -1;
}
}
(warning, this is untested)
Simpler way would be array_multisort
$data = array(
'a' => array( 'type' => 't1', 'weight' => 1, 'text' => 'text1' ),
'b' => array( 'type' => 't1', 'weight' => 3, 'text' => 'text2' ),
'c' => array( 'type' => 't2', 'weight' => 5, 'text' => 'text3' ),
'd' => array( 'type' => 't1', 'weight' => 2, 'text' => 'text4' ),
'e' => array( 'type' => 't2', 'weight' => 4, 'text' => 'text5' ),
'f' => array( 'type' => 't2', 'weight' => 4, 'text' => 'text6' )
);
// Obtain a list of columns
foreach ($data as $key => $row) {
$type[$key] = $row['type'];
$weight[$key] = $row['weight'];
}
array_multisort($type, SORT_ASC, $weight, SORT_ASC, $data);
Plus this works if you add any number of types you want sorted in the same way.
Helper function:
function arrayColumnSort(&$array, $directions) {
// collect columns
$columnNames = array_keys($directions);
$columns = array();
foreach ($array as $row) {
foreach ($columnNames as $columnName) {
if (!isset($columns[$columnName])) {
$columns[$columnName] = array();
}
$columns[$columnName][] = isset($row[$columnName]) ? $row[$columnName] : null;
}
}
// build array_multisort params
$params = array();
foreach ($directions as $columnName => $direction) {
$params = array_merge(
$params,
array($columns[$columnName]),
is_array($direction) ? $direction : array($direction)
);
}
$params[] =& $array;
// sort
call_user_func_array('array_multisort', $params);
}
Call:
arrayColumnSort($data, array(
'type' => SORT_ASC,
'weight' => SORT_ASC,
));