樹的字符串路徑 (JavaScript) (String-path to Tree (JavaScript))


問題描述

樹的字符串路徑 (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 FourgeaudAlex L)

參考文件

  1. String‑path to Tree (JavaScript) (CC BY‑SA 2.5/3.0/4.0)

#reduce #javascript #tree-structure






相關問題

Lapack 的行縮減 (Lapack's row reduction)

泡菜cython類 (pickle cython class)

將列表列表減少為字典,以子列表大小為鍵,出現次數為值 (Reduce list of list to dictionary with sublist size as keys and number of occurances as value)

使用 map/reduce 在列表中添加一對數字的差異 (Adding difference of pair of numbers in list using map/reduce)

Python 2.7:使用 reduce 驗證元素是否在列表中 (Python 2.7: Using reduce to verify that elements are in a list)

使用 map/reduce 計算總數 (Using map/reduce to calculate totals)

Swift reduce - 為什麼 value 是可選的? (Swift reduce - why is value optional?)

獲取具有對像一鍵值的數組的平均值 - Javascript (Get the avarage value of array with objects one key value - Javascript)

如何將數據數組轉換為在顫振/飛鏢中展開或折疊的小部件列表? (How to convert an array of data to a list of widgets with expand or fold in flutter/dart?)

樹的字符串路徑 (JavaScript) (String-path to Tree (JavaScript))

如何重命名對像數組中對象的所有鍵? (How does one rename all of an object's keys within an array of objects?)

使用reduce轉換一個js對象 (transform a js object using reduce)







留言討論