Reputation: 85
I'm trying to build a tree-map from categories.
I have the categories (I have a lot of categories and I want to remove duplicates and show them in a tree-map view)
$cat = array(
"Sneakers/Men",
"Sneakers/Women",
"Accessories/Jewellery/Men",
"Accessories/Jewellery/Women",
"Accessories/Jewellery/Men
");
...and I want them like this
$categories = array(
"Sneakers" => array(
"Men" => array(),
"Women" => array()
),
"Accessories" => array(
"Jewellery" => array(
"Men" => array(),
"Women" => array()
)
)
);
to print them like this
- Sneakers
-- Men
-- Women
- Accessories
-- Jewellery
--- Men
--- Women
Upvotes: 0
Views: 364
Reputation: 4482
The most simple way is to use references, like this:
$out = [];
foreach ($cat as $str) {
$lookup =& $out;
foreach (explode("/", $str) as $part) {
$lookup =& $lookup[$part];
if (!isset($lookup)) {
$lookup = [];
}
}
}
$lookup
initially refers to the whole expected result, then the reference is extended at each step to follow the path of nested members.
Note that each new member added looks like member-name => []
, so that actually even final leaves are arrays: it may seem a bit weird, but is a pretty way to have a reduced code (each member is always ready to receive children).
And it's not a difficulty, though, to use the resulting array to then print it like the OP asked:
function nest_print($src, $level = 0) {
$prefix = '<br />' . str_repeat('- ', ++$level);
foreach ($src as $key => $val) {
echo $prefix . $key;
if ($val) {
nest_print($val, $level);
}
}
}
nest_print($out);
EDIT
Here is an alternate solution, including the count of final leaves, as asked by the OP in his comment:
$out = [];
foreach ($cat as $str) {
$lookup =& $out;
$parts = explode("/", $str);
foreach ($parts as $part) {
$lookup =& $lookup[$part];
if (!isset($lookup)) {
$lookup = [];
}
// when $part is a final leaf, count its occurrences
if ($part == end($parts)) {
$lookup = is_array($lookup) ? 1 : ++$lookup;
}
}
}
(might likely be improved in a more elegant way, though)
And here is how to modify the print-result snippet accordingly:
function nest_print($src, $level = 0) {
$prefix = '<br />' . str_repeat('- ', ++$level);
foreach ($src as $key => $val) {
echo $prefix . $key;
if (is_array($val)) {
nest_print($val, $level);
} else {
echo ': ' . $val;
}
}
}
nest_print($out);
Upvotes: 2
Reputation: 287
Try this:
<?php
$cat = array(
"Sneakers/Men",
"Sneakers/Women",
"Accessories/Jewellery/Men",
"Accessories/Jewellery/Women",
"Accessories/Jewellery/Men
");
function buildTree($categories, $result = []){
$temp = [];
foreach($categories as $categoryString){
$catParts = explode('/',$categoryString);
if(count($catParts) > 1){
$temp[$catParts[0]][] = str_replace($catParts[0].'/','',$categoryString);
} else {
$temp[$catParts[0]] = [];
}
}
foreach($temp as $elemName => $elemVal){
$result[$elemName] = buildTree($elemVal);
}
return $result;
}
var_dump(buildTree($cat));
Upvotes: 2