問題描述
樹的字符串路徑 (JavaScript) (String‑path to Tree (JavaScript))
我有一個字符串格式的路徑數組,如下所示:
[
{ _id: 'women/clothes/tops', count: 10 },
{ _id: 'women/clothes/suits', count: 5 },
{ _id: 'women/accessories', count: 2 },
{ _id: 'men/clothes', count: 1 },
]
我想將它們分組為這樣的樹結構:
[
{
_id: 'women',
count: 17,
children: [
{
_id: 'clothes',
count: 15,
children: [
{ _id: 'tops', count: 10 },
{ _id: 'suits', count: 5 }
]
},
{
_id: 'accessories',
count: 2
}
]
},
{
_id: 'men',
count: 1,
children: [
{
_id: 'clothes',
count: 1
}
]
}
]
我會想像一種遞歸函數調用reduce方法。但我不知道到底是怎麼回事。
編輯:
我設法接近了這個解決方案。但是我仍然得到一個空對象鍵,當沒有孩子時,我無法設法沒有 children 鍵:
const getTree = (array) => {
return array.reduce((a, b) => {
const items = b._id.replace('\/', '').split('/')
return construct(a, b.count, items)
}, {})
}
const construct = (a, count, items) => {
const key = items.shift()
if(!a[key]) {
a[key] = {
_id: key,
count: count,
children: []
}
a[key].children = items.length > 0 ? construct(a[key].children, count, items) : null
}
else {
a[key].count += count
a[key].children = items.length > 0 ? construct(a[key].children, count, items) : null
}
return a
}
</code></pre>
參考解法
方法 1:
I created an object tree first and then converted that to your array of objects with children structure.
Note: I used a _count
property on each object in the intermediate structure so that when looping over the keys later (when creating the final structure), I could ignore both _id
and _count
easily, and loop over only the "real children" keys, which don't start with _
.
I did not look at your current attempt/solution before writing this, so mine looks quite different.
<div class="snippet" data‑lang="js" data‑hide="false" data‑console="true" data‑babel="false">
const origData = [
{ _id: 'women/clothes/tops', count: 10 },
{ _id: 'women/clothes/suits', count: 5 },
{ _id: 'women/accessories', count: 2 },
{ _id: 'men/clothes', count: 1 },
];
const newObj = {};
for (let obj of origData) {
//console.log(obj)
const tempArr = obj._id.split('/');
let tempHead = newObj; // pointer
for (let idx in tempArr) {
let head = tempArr[idx];
if (!tempHead.hasOwnProperty(head)) {
tempHead[head] = {};
}
tempHead = tempHead[head];
tempHead._id = head;
const currCount = tempHead._count || 0;
tempHead._count = currCount + obj.count;
}
tempHead._count = obj.count;
}
console.log(newObj);
const finalArr = [];
let tempArrHead = finalArr; // pointer
let tempObjHead = newObj; // pointer
function recursiveStuff(currObj, currArr, copyObj) {
let hasChildren = false;
const keys = Object.keys(currObj).filter(a => !a.startsWith("_"));
for (let key of keys) {
hasChildren = true;
const obj = {
_id: currObj[key]._id,
count: currObj[key]._count || 0,
children: [],
};
currArr.push(obj);
recursiveStuff(currObj[key], obj.children, obj)
}
if (hasChildren == false) {
// console.log(copyObj);
// there might be a more elegant way, but this works:
delete copyObj.children;
}
}
recursiveStuff(tempObjHead, tempArrHead)
console.log(finalArr);
.as‑console‑wrapper{
max‑height: 100% !important;
}
Intermediate Structure:
{
"women": {
"_id": "women",
"_count": 17,
"clothes": {
"_id": "clothes",
"_count": 15,
"tops": {
"_id": "tops",
"_count": 10
},
"suits": {
"_id": "suits",
"_count": 5
}
},
"accessories": {
"_id": "accessories",
"_count": 2
}
},
"men": {
"_id": "men",
"_count": 1,
"clothes": {
"_id": "clothes",
"_count": 1
}
}
}
Final Structure:
[
{
"_id": "women",
"count": 17,
"children": [
{
"_id": "clothes",
"count": 15,
"children": [
{"_id": "tops", "count": 10},
{"_id": "suits", "count": 5}
]
},
{"_id": "accessories", "count": 2}
]
},
{
"_id": "men",
"count": 1,
"children": [
{"_id": "clothes", "count": 1}
]
}
]
(by Benjamin Fourgeaud、Alex L)
參考文件