通过属性对对象使用嵌套约简

时间:2019-01-10 08:48:22

标签: javascript

我有这样的数据:

const data = [
  { id: 1, cat: "human", age: "10" },
  { id: 2, cat: "human", age: "20" },
  { id: 3, cat: "human", age: "10" },
  { id: 4, cat: "animal", age: "10" },
  { id: 5, cat: "animal", age: "20" },
  { id: 6, cat: "animal", age: "10" },
  { id: 7, cat: "alien", age: "10" },
  { id: 8, cat: "alien", age: "20" },
  { id: 9, cat: "alien", age: "10" },
];

我想像这样对数据进行分组:

const gr = {
  human: {
    all: [
      { id: 1, cat: "human", age: "10" },
      { id: 2, cat: "human", age: "20" },
      { id: 3, cat: "human", age: "10" },
    ],
    ages: {
      "10": [
        { id: 1, cat: "human", age: "10" },
        { id: 3, cat: "human", age: "10" },
      ],
      "20": [
        { id: 2, cat: "human", age: "20" },
      ],
    }
  },
  animal: {...},
  alien: {...},
}

我首先要这样减少:

const gr = data.reduce((acc, el) => {
  const { cat } = el;
  acc[cat] = acc[cat] || { all: [] };
  acc[cat].all.push(el);

  return acc;
}, {});

但是我不能在这里做嵌套的减少。我可以这样单独做:

const grAge = gr.human.all.reduce((acc,el) => {
    const {age} = el;
    acc[age] = acc[age] || [];
    acc[age].push(el);

    return acc;
  },{});

gr.human["ages"] = grAge;

但是显然,这不是那么有效,需要更多的工作。也许像这样:

Object.keys(gr).forEach(key => {
  const grAge = gr[key].all.reduce((acc,el) => {
    const {age} = el;
    acc[age] = acc[age] || [];
    acc[age].push(el);

    return acc;
  },{});

  gr[key]["ages"] = grAge;
});

我可以一步一步加入这些减法吗?

如果我可以使用其他任何好的方法,则不需要使用reduce方法。

2 个答案:

答案 0 :(得分:3)

您可以采用单循环方法,将所需的结构分配给all或嵌套结构。

如果您希望获得更动态的版本,则需要简化每个嵌套级别的结果结构(这意味着年龄级别将包含all属性)。

const
    data = [{ id: 1, cat: "human", age: "10" }, { id: 2, cat: "human", age: "20" }, { id: 3, cat: "human", age: "10" }, { id: 4, cat: "animal", age: "10" }, { id: 5, cat: "animal", age: "20" }, { id: 6, cat: "animal", age: "10" }, { id: 7, cat: "alien", age: "10" }, { id: 8, cat: "alien", age: "20" }, { id: 9, cat: "alien", age: "10" }],
    result = data.reduce((r, o) => {
        r[o.cat] = r[o.cat] || { all: [], ages: {} };        
        r[o.cat].all.push(o);
        r[o.cat].ages[o.age] = r[o.cat].ages[o.age] || [];
        r[o.cat].ages[o.age].push(o);
        return r;
    }, {});

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 1 :(得分:1)

另一种方法是使用Sets获取每个唯一的类别和年龄,然后将其简化为最终的JSON:

编辑:似乎Stack Overflow片段不喜欢它,但是在浏览器控制台中执行它会给出正确的结果

const data = [
	{ id: 1, cat: "human", age: "10" },
	{ id: 2, cat: "human", age: "20" },
	{ id: 3, cat: "human", age: "10" },
	{ id: 4, cat: "animal", age: "10" },
	{ id: 5, cat: "animal", age: "20" },
	{ id: 6, cat: "animal", age: "10" },
	{ id: 7, cat: "alien", age: "10" },
	{ id: 8, cat: "alien", age: "20" },
	{ id: 9, cat: "alien", age: "10" },
];

const output = [...new Set(data.map(thing => thing.cat))].reduce((acc, category) => {
	const catData = data.filter(thing => thing.cat === category)

	return {
		[category]: {
			all: catData,
			ages : [...new Set(catData.map(catThing => catThing.age))].reduce((catAcc, age) => ({
				[age]: [...catData.filter(catThing => catThing.age === age)],
				...catAcc
			}), {})
		},
		...acc
	}
}, {})

console.log(output)
.as-console-wrapper { max-height: 100% !important; top: 0; }