JS数组拉平以及构建Tree数组

146 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天,点击查看活动详情

前言

通常我们在项目经常会遇到嵌套结构的数组数据,对于一些嵌套层级不多的数据,我们比较好处理,但是对于一些嵌套层级比较深的数据,我们在处理数据的时候会比较麻烦,有的时候甚至会花费比较多的时间来处理这些数据,本文今天就来探讨一下,是否可以快速的来对这些数据做处理。

处理方法

对于一般的嵌套数据,形如 [ [] ] 数组套数组这种,我们在能够使用ES6 语法的情况下,可以直接使用flat 方法来对数据进行拉平。

const arr = [[1, 2, [1]], 2];
const newArr = arr.flat(); // [1, 2, 1, 2];

在使用flat 方法的情况,我们还可以传值,用来控制我们需要拉平的次数

const arr = [[1, 2, [1]], 2];
const newArr = arr.flat(1); // [1, 2, [1], 2];
const newArr2 = arr.flat(2); // [1, 2, 1, 2];

那么当我们不使用ES6 的语法,直接使用ES5 的语法,又该怎么去处理呢?

答案很简单,只需要参考下面写法:

const myFlat = (arr) => {
    return arr.reduce((acc, cv, index) => {
        const value = Array.isArray(cv) ? myFlat(cv) : [cv];
        return [
            ...acc,
            ...value
        ]
    }, [])
}
const arr = [[1, 2, [1]], 2];
const newArr = myFlat(arr); // [1, 2, 1, 2];

那么,如果我们需要对层级进行控制,又该怎么办呢?

const myFlat = (arr, depth) => {
    if (depth <= 0) return arr;
    return arr.reduce((acc, cv, index) => {
        const value = Array.isArray(cv) ? myFlat(cv, depth-1) : [cv];
        return [
            ...acc,
            ...value
        ]
    }, [])
}
const arr = [[1, 2, [1]], 2];
const newArr = myFlat(arr, 1); // [1, 2, [1], 2];
const newArr2 = myFlat(arr, 2); // [1, 2, 1, 2];

项目应用

但是通常我们在项目中遇到的嵌套数据比较少是 [ [] ] 数组直接嵌套数据,可能更多的是Tree 结构的数据:

[
    {
        value: 'a',
        label: 'a',
        children: [
            {
                value: 'a-1',
                label: 'a-1'
            }
        ]
    }
]

当我们遇到这样的数据结构的时候,只需要将上面ES5 的方法做一定的变形处理即可:

const myFlat = (options = [], parentId) => {
    return options?.reduce((acc, cv, index) => {
        return [
            ...acc, 
            { ...cv, parentId },
            ...myFlat(cv.children, cv.value)
        ]
    }, []);
}
const options = [
    {
        value: 'a',
        label: 'a',
        children: [
            {
                value: 'a-1',
                label: 'a-1'
            }
        ]
    }
];

const newOptions = myFlat(options);
/** 
[
    {
        value: 'a',
        label: 'a',
        children: [
            {
                value: 'a-1',
                label: 'a-1'
            }
        ]
    },
    {
        value: 'a-1',
        label: 'a-1',
        parentId: 'a'
    }
] 
*/

至此,我们就可以对一定的嵌套数据进行拉平处理,方便我们在一层数组下面,进行查找数据和匹配数据。

拉平数组反向构建Tree数组

在项目中,我们有的时候可能对拉平后的数组做了一定的处理,然后我们需要将拉平后的数组反向构建成Tree 结构的数组,那么,我们只需要将拉平后的数组做如下处理即可:

const buildTree = (arr) => {
    const root = { id: 'root', children: [] };
    const nodes = { [root.id]: root };
    
    const items = arr.map(item => ({ ...item, children: [] }));
    
    for (const item of items) {
        const { value, label, children } = item;
        const parentId = item.parentId ?? root.id;
        const parent = nodes[parentId] ?? items.find(i => i.value === parentId);
        
        nodes[value] = { ...item };
        parent.children.push(item);
    }
    
    return root.children;
}

const arr = [
    {
        value: 'a',
        label: 'a',
        children: [
            {
                value: 'a-1',
                label: 'a-1'
            }
        ]
    },
    {
        value: 'a-1',
        label: 'a-1',
        parentId: 'a'
    }
];
const newArr = buildTree(arr);
/** 
[
    {
        value: 'a',
        label: 'a',
        children: [
            {
                value: 'a-1',
                label: 'a-1',
                parentId: 'a',
                children: []
            }
        ]
    },
]
*/

总结

至此,我们知道了如何将嵌套数组进行拉平,以及如何将对应的拉平数组重新构建成Tree 结构的数组。这些方法对于我们在项目中碰到对应的结构数据,还是非常有用的。