I have a table that contains a directory structure. There is an item ID and a DirectoryID. The DirectoryID refers to an item ID and is, as such, a child directory under the parent directory. An example below:
# ID, DirectoryID, DirectoryName
'1', '0', 'Root Dir'
'2', '0', 'Another Root Dir'
'3', '2', 'TESTING456'
'4', '3', 'TESTING789'
'5', '1', 'TESTINGMORE'
'6', '4', 'RANDOM DIR'
Using PHP, how do I build that into an array that looks like the one below?
$array = [
[2 => 'Another Root Dir',3 => 'TESTING456', 4 => 'TESTING789', 6 => 'RANDOM DIR'],
[1 => 'Root Dir',5 => 'TESTINGMORE']
];
CodePudding user response:
Loop through the root nodes and then for each children.
$dirs = [
['1', '0', 'Root Dir'],
['2', '0', 'Another Root Dir'],
['3', '2', 'TESTING456'],
['4', '3', 'TESTING789'],
['5', '1', 'TESTINGMORE'],
['6', '4', 'RANDOM DIR'],
];
$array = [];
foreach (array_filter($dirs, fn($dir) => '0' === $dir[1]) as $root) {
$parent = $root[0];
$current = [$parent => $root[2]];
while ($children = array_filter($dirs, fn($dir) => $dir[1] === $parent)) {
$child = reset($children);
$parent = $child[0];
$current[$parent] = $child[2];
}
$array[] = $current;
}
print_r($array);
Output
Array
(
[0] => Array
(
[1] => Root Dir
[5] => TESTINGMORE
)
[1] => Array
(
[2] => Another Root Dir
[3] => TESTING456
[4] => TESTING789
[6] => RANDOM DIR
)
)
CodePudding user response:
If you mean list of all paths for directory array, first create tree then we'll iterate it. I will start with JS because it's more fun.
// ID, DirectoryID, DirectoryName
var arr = [
['1', '0', 'Root Dir'],
['2', '0', 'Another Root Dir'],
['3', '2', 'TESTING456'],
['4', '3', 'TESTING789'],
['5', '1', 'TESTINGMORE'],
['6', '4', 'RANDOM DIR']
]
console.log(do_arr(arr));
function do_arr(arr) {
// grouping by id for easy access
var grouped = arr.reduce(function(agg, [id, parent, name]) {
agg[id] = { id, parent, name }
return agg;
}, {})
// we want 1 root for all others
grouped['0'] = { id: 0, name: 'really-main-root' }
// creating tree with children
arr.forEach(function([id, parent, name]) {
grouped[parent].children = grouped[parent].children || []
grouped[parent].children.push(id)
})
// doing all_paths
var result = [];
function iterate(obj, so_far) {
if (obj.children) {
obj.children.forEach(function(child_id) {
iterate(grouped[child_id], so_far.concat({
id: child_id,
name: grouped[child_id].name
}));
})
} else {
result.push(so_far)
}
}
iterate(grouped[0], [])
return result;
}
.as-console-wrapper {
max-height: 100% !important
}
And here's the PHP version:
$arr = [
['1', '0', 'Root Dir'],
['2', '0', 'Another Root Dir'],
['3', '2', 'TESTING456'],
['4', '3', 'TESTING789'],
['5', '1', 'TESTINGMORE'],
['6', '4', 'RANDOM DIR'],
];
print_r(do_arr($arr));
function do_arr($arr)
{
// grouping by id for easy access
$grouped = array_reduce($arr, function ($agg, $item) {
$id = $item[0];
$parent = $item[1];
$name = $item[2];
$agg[$id] = compact('id', 'parent', 'name');
return $agg;
}, []);
// we want 1 root for all others
$grouped['0'] = ['id' => '0'];
// creating tree with children
foreach ($grouped as $item) {
extract($item);
if (isset($parent)) {
$grouped[$parent]["children"][] = $id;
}
}
// doing all_paths
$result = [];
function iterate($obj, $so_far = [], $grouped, &$result)
{
if (isset($obj["children"])) {
foreach ($obj["children"] as $child_id) {
if ($child_id) {
iterate($grouped[$child_id], array_merge($so_far, [$child_id => $grouped[$child_id]['name']]), $grouped, $result);
}
}
} else {
$result[] = $so_far;
}
}
iterate($grouped['0'], [], $grouped, $result);
return $result;
}