Как суммировать все листовые узлы вложенного массива объектов Javascript?

1

В настоящее время у меня есть вложенный массив объектов 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;
                          })

                      };
                  }
              };

Что-то вроде этого, но использование функции уменьшения возвращает плоский массив. Если да, то как мне вставить этот плоский массив обратно в мои листовые узлы?

Я смог получить ВСЕ листовые узлы и заполнить их, поэтому мой ожидаемый результат - это что-то вроде этого, но я хочу, чтобы он соответствовал каждому из родителей.

МОИ ДАННЫЕ: 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}
      }
    ]
  }
]
Теги:
arrays
tree

1 ответ

0
Лучший ответ
  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));
  • 0
    Потрясающая работа. Можете ли вы добавить немного больше к своему ответу? Я хотел бы, чтобы у конечных узлов было какое-либо свойство метки, например, name: "Cellophane Tape:, value: 79.7194
  • 0
    out = []; Object.keys (mappedData) .forEach (function (d) {out.push ({имя: d, значение: mappedData [d]});})
Показать ещё 7 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню