首页 > 解决方案 > 将对象数组转换为对象分组数组 Typescript

问题描述

我正在尝试转换这样的对象数组:

[{grandParentField:'grandParent1', parentField:'parent1', childField: 'child1'},
 {grandParentField:'grandParent1', parentField:'parent1', childField: 'child2'},
 {grandParentField:'grandParent2', parentField:'parent1', childField: 'child3'},
 {grandParentField:'grandParent2', parentField:'parent2', childField: 'child4'}]

变成这种形式:

[
{
  text: 'grandparent1',
  items: [
    {
      text: 'parent1',
      items: [{ text: 'child1' }, { text: 'child2' }]
    }
  ]
},
{
  text: 'grandparent2',
  items: [
    {
      text: 'parent1',
      items: [{ text: 'child3' }]
    },
    {
      text: 'parent2',
      items: [{ text: 'child4' }]
    }
  ]
}

]

这个线程与我想要的相似,但不完全是。

孩子永远是独一无二的,但父母可以有多个祖父母。

老实说,我已经尝试了很多事情,我什至不确定要包括哪一个作为最接近我的例子。

像这样的东西,但能够接收一组对象,并抽出{text: string, items:[{text: string, items:[{text:string]]}结构:

var groupBy = function(xs, key) {
  return xs.reduce(function(rv, x) {
    (rv[x[key]] = rv[x[key]] || []).push(x);
    return rv;
  }, {});
};

console.log(groupBy(['one', 'two', 'three'], 'length'));

// => {3: ["one", "two"], 5: ["three"]}

标签: arraystypescriptdata-transform

解决方案


不要对类型太疯狂,我会说你希望你的输出是这种形状:

interface Tree {
    text: string,
    items?: Tree[]
}

因此,让我们创建一个名为的函数,该函数group()将您的数组和您想要按照它们应该被处理的顺序处理的键列表。因此,对于您的示例,它将像这样使用:

const data = [
    { grandParentField: 'grandParent1', parentField: 'parent1', childField: 'child1' },
    { grandParentField: 'grandParent1', parentField: 'parent1', childField: 'child2' },
    { grandParentField: 'grandParent2', parentField: 'parent1', childField: 'child3' },
    { grandParentField: 'grandParent2', parentField: 'parent2', childField: 'child4' }
];
    
const groupedData = group(data, "grandParentField", "parentField", "childField");

这是 的实现group()

function group(data: Array<Record<string, string>>, key: string, ...otherKeys: string[]): Tree[] {
    const objMap: Record<string, any[]> = {}
    for (const d of data) {
        if (!(d[key] in objMap)) {
            objMap[d[key]] = []
        }
        objMap[d[key]].push(d);
    }
    return Object.keys(objMap).map(k => otherKeys.length ?
        {
            text: k,
            items: group(objMap[k], otherKeys[0], ...otherKeys.slice(1))
        } : {
            text: k
        }
    );

}

首先,我们将元素 from 分组data到一个名为 的数组字典中objMap,其中每个元素d进入objMapat的键d[key](因此第一个元素进入名为"grandParent1"if keyis的键"grandParentField")。

完成此分组后,我们通过遍历objMap的键返回一个新数组。如果我们没有,我们只返回一个使用键作为字段的元素otherKeys数组。如果我们确实有其他键,那么我们需要递归调用存储在正确键中的元素。{text: string}objMaptextgroup()objMap

您可以验证这是否适用于您的示例:

console.log(JSON.stringify(groupedData, undefined, 2));
/* [
  {
    "text": "grandParent1",
    "items": [
      {
        "text": "parent1",
        "items": [
          {
            "text": "child1"
          },
          {
            "text": "child2"
          }
        ]
      }
    ]
  },
  {
    "text": "grandParent2",
    "items": [
      {
        "text": "parent1",
        "items": [
          {
            "text": "child3"
          }
        ]
      },
      {
        "text": "parent2",
        "items": [
          {
            "text": "child4"
          }
        ]
      }
    ]
  }
] */

Playground 代码链接


推荐阅读