I would like to set level to each array that has children key in nested array. More deep that array then more big the level value.
Here's what I'm expected:
<?php
$array = array(
array(
'id' => 1,
'children' => array(
array(
'id' => 6,
'children' => array(
array(
'id' => 7,
),
array(
'id' => 8,
)
),
// Expected
'level' => '2',
),
array(
'id' => 9,
)
),
// Expected
'level' => '1'
),
array(
'id' => 2,
'children' => array(
array(
'id' => 10,
),
array(
'id' => 13,
'children' => array(
array(
'id' => 14,
),
array(
'id' => 19,
'children' => array(
array(
'id' => 20,
),
array(
'id' => 21,
),
array(
'id' => 22,
),
array(
'id' => 23,
),
)
// Expected
'level' => '3'
)
),
// Expected
'level' => '2'
),
),
// Expected
'level' => '1'
)
);
So far I make a function to set the level that has children key in nested array. But, the result is not what I'm expected.
<?php
$array = array(
array(
'id' => 1,
'children' => array(
array(
'id' => 6,
'children' => array(
array(
'id' => 7,
),
array(
'id' => 8,
)
),
// Expected
// 'level' => '2',
),
array(
'id' => 9,
)
),
// Expected
// 'level' => '1'
),
array(
'id' => 2,
'children' => array(
array(
'id' => 10,
),
array(
'id' => 13,
'children' => array(
array(
'id' => 14,
),
array(
'id' => 19,
'children' => array(
array(
'id' => 20,
),
array(
'id' => 21,
),
array(
'id' => 22,
),
array(
'id' => 23,
),
)
// Reality result
// 'level' => '4'
)
),
// Reality result
// 'level' => '3'
),
),
// Reality result
// 'level' => '2'
)
);
As you can see in Reality result comment is level 2, level 3, and level 4. What I'm expected the result is level 1, level 2, level 3, level (n+1). When there's not any children in the deeper array then the level value must be reset to level 1.
Here's my code that get the reality result:
<?php
function updateTreeArray(&$array, $level = 1) {
foreach ($array as $key => &$value) {
if (isset($value['children'])) {
$value['level'] = $level;
$level = setLevel($value['children'], $level);
}
if (is_array($value)) {
updateTreeArray($value, $level);
}
}
return $array;
}
function setLevel($array, $level) {
foreach ($array as $key => &$value) {
if (isset($value['children'])) {
$level += 1;
setLevel($value['children'], $level);
}
}
return $level;
}
print_r(updateTreeArray($array));
Could you please help me what should I do to achieve the expected result? Thanks.
One recursive function is enough.
function updateTreeArray(&$array, $level = 1)
{
foreach($array as &$item) {
if (array_key_exists('children', $item) && is_array($item['children'])) {
$item['level'] = $level;
updateTreeArray($item['children'], $level + 1);
}
}
}
updateTreeArray($array);
print_r($array);
fiddle
Related
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;
}
Given this array and a name (e.g. 'def'), how do I get the containing array, or key?
$all = array(
'0' => array(
'name' => 'abc'
'option' => 1,
),
'1' => array(
'name' => 'def'
'option' => 1,
),
'2' => array(
'name' => 'ghi'
'option' => 0,
),
);
What's the best way to return this array given 'def'?
$single = array(
'name' => 'def'
'option' => 1,
);
I could do something like this:
$single = array();
foreach ($all as $key => $value) {
if ($value['name'] == 'def') {
$single = $all[$key];
}
}
Or prerender the keys in the array so that it looks like this:
$all = array(
'abc' => array(
'name' => 'abc'
'option' => 1,
),
'def' => array(
'name' => 'def'
'option' => 1,
),
'ghi' => array(
'name' => 'ghi'
'option' => 0,
),
);
$single = $all['def'];
But I'm wondering if there's a shorter php function for that.
You could use array_filter:
array_filter($array, function($var){
return $var["name"] == "def";
});
I have an array like this:
array(
array(
'id' => 1,
'parent_id' => null
),
array(
'id' => 2,
'parent_id' => 1
),
array(
'id' => 3,
'parent_id' => 2
),
array(
'id' => 4,
'parent_id' => null
),
array(
'id' => 5,
'parent_id' => 4
)
);
How can i find all the childrens of a given parent_id including all grand children? For example the function will return 2,3 for parent_id 1.
Thanks.
// I corrected the array to fit your result 1 => 2,3
<?php
$test = array(
array(
'id' => 1,
'parent_id' => null
),
array(
'id' => 2,
'parent_id' => 1
),
array(
'id' => 3,
'parent_id' => 1
),
array(
'id' => 4,
'parent_id' => null
),
array(
'id' => 5,
'parent_id' => 4
)
);
// 1_2+3
$parent_childs = ARRAY();
foreach ($test AS $index => $child) {
if (!isset($child['parent_id'])) { continue; }
$parent_childs[$child['parent_id']][] = $child['id'];
}
echo '<pre>';var_dump($parent_childs); echo '</pre>';
?>
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,
));