【问题标题】:How to sum up all the leaf nodes of a nested Javascript object array?如何总结嵌套 Javascript 对象数组的所有叶节点?
【发布时间】:2018-09-18 09:34:39
【问题描述】:

目前我有一个嵌套的 Javascript 对象数组,它有许多同名但值不同的叶节点

{
  "children": [
    {
      "name": "Central",
      "children": [
        {
          "name": "Cellophane `Tape",
          "value": 10.528979999999999
        },
        {
          "name": "Cellophane Tape",
          "value": 10.529
        },
        {
          "name": "File Separator",
          "value": 10.529
        },
        {
          "name": "Hard Cover File",
          "value": 10.529
        },
        {
          "name": "Highlighter",
          "value": 10.529
        },
        {
          "name": "Office Chair",
          "value": 10.529
        },
        {
          "name": "Pencil",
          "value": 10.529
        },
        {
          "name": "Tape Dispenser",
          "value": 10.529
        },
        {
          "name": "File Cabinet",
          "value": 21.058
        },
        {
          "name": "Highlighter",
          "value": 21.058
        },
        {
          "name": "Office Chair",
          "value": 21.058
        },
        {
          "name": "Pencil",
          "value": 21.058
        },
        {
          "name": "Plastic Comb Binding",
          "value": 21.058
        },
        {
          "name": "Tape Dispenser",
          "value": 21.058
        },
        {
          "name": "White Board Markers",
          "value": 21.058
        },
        {
          "name": "File Separator",
          "value": 23.273360000000004
        },
        {
          "name": "Binder",
          "value": 23.2734
        },
        {
          "name": "Cellophane Tape",
          "value": 23.2734
        },
        {
          "name": "File Separator",
          "value": 23.2734
        },
        {
          "name": "Hard Cover File",
          "value": 23.2734
        },
        {
          "name": "Highlighter",
          "value": 23.2734
        },
        {
          "name": "Plastic Comb Binding",
          "value": 23.2734
        },
        {
          "name": "Tape Dispenser",
          "value": 23.2734
        },
        {
          "name": "White Board Markers",
          "value": 23.2734
        },
        {
          "name": "Binder",
          "value": 64.0017
        },
        {
          "name": "Eraser",
          "value": 64.0017
        },
        {
          "name": "File Separator",
          "value": 64.0017
        },
        {
          "name": "Office Chair",
          "value": 64.0017
        },
        {
          "name": "Plastic Comb Binding",
          "value": 64.0017
        },
        {
          "name": "Tape Dispenser",
          "value": 64.0017
        },
        {
          "name": "Binder",
          "value": 64.00174
        },
        {
          "name": "Tape Dispenser",
          "value": 64.00174
        },
        {
          "name": "Binder",
          "value": 67.2899
        },
        {
          "name": "Highlighter",
          "value": 67.2899
        },
        {
          "name": "Office Chair",
          "value": 67.2899
        },
        {
          "name": "Plastic Comb Binding",
          "value": 67.2899
        },
        {
          "name": "Tape Dispenser",
          "value": 67.2899
        },
        {
          "name": "Cellophane Tape",
          "value": 74.2509
        },
        {
          "name": "Office Chair",
          "value": 74.2509
        },
        {
          "name": "Pencil",
          "value": 74.2509
        },
        {
          "name": "Plastic Comb Binding",
          "value": 74.2509
        },
        {
          "name": "White Board Markers",
          "value": 74.2509
        },
        {
          "name": "Cellophane Tape",
          "value": 79.7194
        }
      ]
    }
  ]
}

因此,我想做的是遍历这个数组的所有叶子节点,然后像这样根据每个父节点聚合它

const agregateDeep = x => {
                  if (Array.isArray(x.children)) {
                      x.children = x.children.map(deep);
                      return x;
                  } else {
                      return {
                          x: x.reduce(function (r, o) {
                              (r[o.name]) ? r[o.name] += o.value : r[o.name] = o.value;
                              return r;
                          })

                      };
                  }
              };

类似这样,但使用 reduce 函数返回一个平面数组。如果是这样,那么如何将这个平面数组插入到我的叶节点中?

我能够检索所有叶节点并聚合它,所以我的预期输出是这样的,但我希望它根据每个父节点。

我的数据https://api.myjson.com/bins/gki6c

预期输出:

[
  {
    "name": "Central",
    "children": [
      {
            {"name" : "Cellophane Tape","value":79.7194},
            {"name" : "File Separator","value":64.0017},
            {"name" : "Hard Cover File","value":23.2734},
            {"name" : "Highlighter", "value":67.2899},
            {"name" : "Office Chair","value":74.2509},
            {"name" : "Pencil","value": 74.2509},
            {"name" : "Tape Dispenser","value" : 67.2899},
            {"name" : "File Cabinet","value": 21.058},
            {"name" : "Plastic Comb Binding","value": 74.2509},
            {"name" : "White Board Markers","value": 74.2509},
            {"name" : "Binder","value" : 67.2899},
            {"name" : "Eraser","value": 64.0017}
      }
    ]
  }
]

【问题讨论】:

    标签: javascript arrays tree


    【解决方案1】:
    1. 您可以为找到的名称及其叶节点维护一个hash 跨越对象
    2. 您可以过滤叶节点并将其转换为您想要的, 检查散列中的存在,如果发现将其添加并使用该数组, 否则创建一个新数组,将其推到那里并将数组保存在 哈希。
    3. 您可以过滤掉那些有更多孩子的孩子,然后 递归地调用它们中的每一个(过滤的)孩子来处理 相同的逻辑(它将帮助您不要在 递归堆栈)

    var obj = {"children":[{"name":"Central","children":[{"name":"Cellophane `Tape","value":10.528979999999999},{"name":"Cellophane Tape","value":10.529},{"name":"File Separator","value":10.529},{"name":"Hard Cover File","value":10.529},{"name":"Highlighter","value":10.529},{"name":"Office Chair","value":10.529},{"name":"Pencil","value":10.529},{"name":"Tape Dispenser","value":10.529},{"name":"File Cabinet","value":21.058},{"name":"Highlighter","value":21.058},{"name":"Office Chair","value":21.058},{"name":"Pencil","value":21.058},{"name":"Plastic Comb Binding","value":21.058},{"name":"Tape Dispenser","value":21.058},{"name":"White Board Markers","value":21.058},{"name":"File Separator","value":23.273360000000004},{"name":"Binder","value":23.2734},{"name":"Cellophane Tape","value":23.2734},{"name":"File Separator","value":23.2734},{"name":"Hard Cover File","value":23.2734},{"name":"Highlighter","value":23.2734},{"name":"Plastic Comb Binding","value":23.2734},{"name":"Tape Dispenser","value":23.2734},{"name":"White Board Markers","value":23.2734},{"name":"Binder","value":64.0017},{"name":"Eraser","value":64.0017},{"name":"File Separator","value":64.0017},{"name":"Office Chair","value":64.0017},{"name":"Plastic Comb Binding","value":64.0017},{"name":"Tape Dispenser","value":64.0017},{"name":"Binder","value":64.00174},{"name":"Tape Dispenser","value":64.00174},{"name":"Binder","value":67.2899},{"name":"Highlighter","value":67.2899},{"name":"Office Chair","value":67.2899},{"name":"Plastic Comb Binding","value":67.2899},{"name":"Tape Dispenser","value":67.2899},{"name":"Cellophane Tape","value":74.2509},{"name":"Office Chair","value":74.2509},{"name":"Pencil","value":74.2509},{"name":"Plastic Comb Binding","value":74.2509},{"name":"White Board Markers","value":74.2509},{"name":"Cellophane Tape","value":79.7194}]}]};
    
    function aggDeep(obj) {
      let hasChildren = o => o.children && o.children.length,
        hasNoChildren = o => !(o.children && o.children.length),
        map = {},
        aggDeepRec = ({
          name,
          children
        }) => {
          if (hasChildren({
              children
            })) {
            let leafs = children.filter(hasNoChildren);
            if (leafs.length) {
              let entry = (map[name] = map[name] || {name, children: {}});
              leafs.forEach(le => {
                entry.children[le.name] = (entry.children[le.name] || 0) + le.value;
              });
            }
            children.filter(hasChildren).forEach(c => aggDeepRec(c));
          }
          return map;
        }
      return Object.entries(aggDeepRec(obj)).reduce((res, [k, v])=>{
        let {name} = v,
        children = Object.entries(v.children).map(([name, value])=> ({name, value}));
        return Object.assign(res, {[k]: {name, children}});
      }, {});
    }
    
    var res = aggDeep(obj);
    
    console.log(JSON.stringify(res, null, 4));

    【讨论】:

    • 惊人的工作。您可以在答案中添加更多内容吗?我希望叶节点具有一些标签属性,例如名称:“玻璃纸胶带:,值:79.7194
    • out = []; Object.keys(mappedData).forEach(function (d) { out.push({ name: d, value: mappedData[d] }); })
    • 可能是这样的?如果您能做到这一点,我会将您的答案标记为有用:)
    • 不确定您到底想要什么。如果您可以显示您想要的确切输出,或者您可以相应地调整代码。
    • 如果您看到我的示例数据,数据具有“名称”和“值”属性。但是,在您的输出中,它只是“玻璃纸胶带”:79.7194。
    猜你喜欢
    • 2022-11-16
    • 2021-12-29
    • 1970-01-01
    • 2020-06-16
    • 2021-10-02
    • 2010-09-18
    • 1970-01-01
    • 2020-04-13
    相关资源
    最近更新 更多