汇总给定级别的树(嵌套对象)

时间:2018-12-21 16:31:39

标签: javascript recursion javascript-objects

我有一棵嵌套对象的树(3层,分别代表建筑物,地板,房间)。叶节点包含房间区域。我想在给定级别(动态提供)下总结该区域,而无需更改源数据。

const data = {
  building1: {
    floor1: {
      room1: {
        area: 0.1,
      },
      room2: {
        area: 0.2,
      }
    },
    floor2: {
      room1: {
        area: 0.3,
      },
      room2: {
        area: 0.4,
      }
    }
  },
  building2: {
    floor1: {
      room1: {
        area: 0.15,
      },
      room2: {
        area: 0.25,
      }
    },
    floor2: {
      room1: {
        area: 0.35,
      },
      room2: {
        area: 0.45,
      }
    }
  },
  level: 3
};

例如,我需要一个1级(建筑物级)摘要来返回看起来像这样的新对象:

{
  building1: {
      area: 1
  },
  building2: {
      area: 1.2
  }
}

我希望能够获得一个像这样的2级摘要:

{
  building1: {
    floor1: {
      area: 0.3
    },
    floor2: {
      area: 0.7
    }
  },
  building2: {
    floor1: {
      area: 0.4
    },
    floor2: {
      area: 0.8
    }
  }
}

累加只是简单的算术和。我可以获取树中任何节点的摘要(组合区域),但是不确定如何克隆源数据并用摘要替换所需级别的数据。

const addAreas = (op1, op2) => ({
  area: op1.area + op2.area
})

const traverseNodeToArea = node => {
  return Object.entries(node).map(([key, val]) =>
    val.hasOwnProperty('area')
      ? val
      : traverseNodeToArea (val)
  ).reduce(addAreas,{
    area: 0
  });
};

如果有帮助,乐意使用lodash。我确信必须有一个简单的解决方案,但我看不到。

traverseNodeToArea基于this answer

1 个答案:

答案 0 :(得分:2)

您可以使用级别计数器,如果级别为零,则获取剩余嵌套区域的总和。

function getSummary(object, level) {
    const getSumOfArea = object => Object.entries(object).reduce((r, [k, v]) => r + (k === 'area' ? v : getSumOfArea(v)), 0);

    if (!object || typeof object !== 'object')
        return object;

    if (level)
        return Object.assign(...Object.entries(object).map(([k, v]) => ({ [k]: getSummary(v, level - 1) })));

    return { area: getSumOfArea(object) };
}

const data = { building1: { floor1: { room1: { area: 0.1, }, room2: { area: 0.2, } }, floor2: { room1: { area: 0.3, }, room2: { area: 0.4, } } }, building2: { floor1: { room1: { area: 0.15, }, room2: { area: 0.25, } }, floor2: { room1: { area: 0.35, }, room2: { area: 0.45, } } }, level: 3 };

console.log(getSummary(data, 0));
console.log(getSummary(data, 1));
console.log(getSummary(data, 2));
console.log(getSummary(data, 3));
.as-console-wrapper { max-height: 100% !important; top: 0; }