0

我有一个字符串格式的路径数组,如下所示:

[
  { _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方法的递归函数。但我不知道具体是怎样的。

编辑 :

我设法接近这个解决方案。但是我仍然得到一个空对象键,当没有孩子时,我无法设法没有孩子键:


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
}
4

1 回答 1

1

我首先创建了一个对象树,然后将其转换为具有子结构的对象数组。

注意:我_count在中间结构中的每个对象上都使用了一个属性,以便稍后循环键(创建最终结构时)时,我可以轻松地忽略两者,_id并且_count只循环“真正的子”键,这些键不会t 开头_

在写这篇文章之前,我没有查看您当前的尝试/解决方案,所以我的看起来完全不同。

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;
}

中间结构:

{
  "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
    }
  }
}

最终结构:

[
  {
    "_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}
    ]
  }
]
于 2021-05-15T13:57:37.323 回答