将树形递归结构的JSON数据扁平化

4,774 阅读1分钟

有时我们需要处理这样的数据:

一个列表内拥有相同属性的Object,就像是列表-记录形式的表数据。区别之处在于每个Object都有一个children属性,而children对应的是另一个这样的列表,也就是说它拥有递归结构。它本质上是一个树的数据结构,每一个Object都是树的结点,children为空的结点就是叶子结点。

而处理这样的数据时,有的时候我们会有这样的需求,就是从根结点开始,去找到通向某个结点的路径。当然既然children是一个Array,那么我们用一个包含array index的array就可以表示一个树上从根结点到某个结点的路径了。然而这种方法可读性比较差,我们不可能靠记忆下标来进行查找。我们通常是通过字符串来表示路径的,比如文件路径和URL,通过一个分隔符“/”来表示层次关系。

在上面图片所示的例子中,所有的记录都包含一个desc属性,我希望用desc属性来表示路径。在我打开的叶子结点中,desc属性的内容是“Coraracoius”,那么通向这个结点的路径看起来就像是这样:

Rerarelt/Coraracoius

那么我要如何穷举这棵树上所有结点的路径呢?大概看起来是这样子:

代码如下:

function prefix(p, obj, delim="/"){
  return Object.fromEntries(Object.entries(obj).map(([k, v]) => [`${p}${delim}${k}`, v]));
}

function flat(entries, pathColKey){
  return entries
  .reduce((acc, entry) => {
    
    // get the actual column value according to the specified key.
    const {[pathColKey]:pathCol, children} = entry;

    const prefixed = children === undefined || children.length === 0
    ? {[pathCol]:entry}                           // for leaf node
    : prefix(pathCol, flat(children, pathColKey)) // for non-leaf node.
    
    return {...acc, ...prefixed}
  }, {})
}