js数组对象如何进行取值计算

首先有两个数组:

listD = [
    {
        id: '1',
        children: [
            {
                id: '1-1',
                children: [
                    { id: '1-1-1', children: [] },
                    { id: '1-1-2', children: [] }
                ]
            },
            { id: '1-2', children: [] }
        ]
    }, {
        id: '2',
        children: [
            { id: '2-1', children: [] },
            { id: '2-3', children: [] }
        ]
    }, {
        id: '3',
        children: [
            { id: '3-1', children: [] },
            { id: '3-2', children: [] }
        ]
    }
]
listc: [
    { id: '2-1', sum: 20 },
    { id: '2-3', sum: 20 },
    { id: '1-1-1', sum: 10 },
    { id: '1-1-2', sum: 10 }
]

实现结果:

list: [
    {
        id: '1',
        children: [
            {
                id: '1-1',
                sum: 20,
                children: [
                    { id: '1-1-1', children: [{ sum: 10 }] },
                    { id: '1-1-2', children: [{ sum: 10 }] }
                ]
            },
            { id: '1-2', children: [] }
        ]
    }, {
        id: '2',
        sum: 40,
        children: [
            { id: '2-1', children: [{ sum: 20 }] },
            { id: '2-3', children: [{ sum: 20 }] }
        ]
    }, {
        id: '3',
        children: [
            { id: '3-1', children: [] },
            { id: '3-2', children: [] }
        ]
    }
]

我的想法是:

先循环找到相同的id,然后把相应的sum及对应的值都拿过去

function jisuan(list){
    for(let i=0; i<list.length; i++){
        if(list[i].children.length>0){
          for(let j = 0; j<list[i].children.length; j++){
            for(let k = 0; k<listc.length; k++){
               if(list[i].children[j].id == listc[k].id){
                list[i].children[j]['sum'] = listc[k].sum
                //list[i]['sum'] += Number(list[i].children[j]['sum'])
              }
            }
          }
        }
        console.log(list, '====')
        //jisu(list[i].children)
      }
}

我只能实现赋值,层层相加的这种不知道怎么弄,我想是如果对应的这个id有值,就在父级添加一个sum字段,没有就不添加,但是研究一天了,也没能计算对 -_-

阅读 2.5k
2 个回答

对于处理层级确定的数据结构,可以使用多重循环。但如果层次过多(比如多于 2 层)就应该使用递归。对于处理层级数不确定的相似数组结构,那不用说,基本上可以确定是递归。当然,递归本身是可以转换成栈+循环的,所以有一些也可以用循环来处理 —— 当然不是按层级的多重循环。

这个问题基本上就是遍历树,对每个节点,从 listc 中去找到对应的 sum 来给节点补充属性。遍历树的过程多数情况是使用递归来完成。可以阅:

// 写一个 workThrought 遍历节点数组及其子节点
// 这里假设子节点在 children 属性中,如果需要更通用性的函数
// 可以加一个指示子节点属性名的参数,或者 getter 函数
// fn 是对节点进行处理的函数
function walkThrough(nodes, fn) {
    nodes.forEach(node => {
        fn(node);
        if (node.children?.length > 0) {
            walkThrough(node.children, fn);
        }
    });
}

// 调用 walkThrought 的时候,指定 node 处理函数
// 就是在 listc 中去按 ID 找对应的 sum,若有,赋值
walkThrough(listD, node => {
    const match = listc.find(c => c.id === node.id);
    if (match) {
        node.sum = match.sum;
    }
});

console.dir(listD, { depth: null });

如果 listc 的数据量比较大,可以通过映射表来优化查找效率,fn 参数传入那里用 IIFE 做个封装

walkThrough(listD, (() => {
    const map = Object.fromEntries(listc.map(({ id, sum }) => [id, sum]));
    return node => {
        const sum = map[node.id];
        if (sum !== undefined) { node.sum = sum; }
    };
})());
const list1 = [{
    id: '1',
    children: [{
        id: '1-1',
        children: [{
            id: '1-1-1',
            children: []
        }, {
            id: '1-1-2',
            children: []
        }]
    }, {
        id: '1-2',
        children: []
    }]
}, {
    id: '2',
    children: [{
        id: '2-1',
        children: []
    }, {
        id: '2-3',
        children: []
    }]
}, {
    id: '3',
    children: [{
        id: '3-1',
        children: []
    }, {
        id: '3-2',
        children: []
    }]
}]

const list2 = [{
    id: '2-1',
    sum: 20
}, {
    id: '2-3',
    sum: 20
}, {
    id: '1-1-1',
    sum: 10
}, {
    id: '1-1-2',
    sum: 10
}]

function walk(list) {
    let currLevelSum = 0
    list.forEach(item=>{
        const sum = walk(item.children) || findItem(list2, item)?.sum  || 0
        currLevelSum += sum
        item.sum = sum
    })
    return currLevelSum
}

function findItem(list, target) {
    return list.find(item=>item.id === target.id)
}

walk(list1)
console.log(list1)

供参考, 如果确认 list 2 只包含叶子节点可以加几个 if 避免多余计算

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题