完全忘了 itemMap[id]还代表了引用 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a Javascript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
Javascript 权威指南第 5 版
Closure: The Definitive Guide
devwolf
V2EX    Javascript

完全忘了 itemMap[id]还代表了引用

  •  
  •   devwolf 2023-04-18 14:22:57 +08:00 1961 次点击
    这是一个创建于 906 天前的主题,其中的信息可能已经有所发展或是发生改变。

    在看一个掘金的帖子 https://juejin.cn/post/6983904373508145189 “扁平数据结构转 Tree”。

    看的时候在想,自己很少用 Map 对象,要不试试用 Map 改造一下,结果改造失败,找了半天原因,靠同事指了出来。

    let arr = [ { id: 1, name: "部门 1", pid: 0 }, { id: 2, name: "部门 2", pid: 1 }, { id: 3, name: "部门 3", pid: 1 }, { id: 4, name: "部门 4", pid: 3 }, { id: 5, name: "部门 5", pid: 4 }, ]; let result = []; function arrayToTree1(items) { const result = []; const itemMap = {}; for (const item of items) { itemMap[item.id] = { ...item, children: [] }; } for (const item of items) { const id = item.id; const pid = item.pid; const treeItem = itemMap[id]; if (pid === 0) { result.push(treeItem); } else { if (!itemMap[pid]) { itemMap[pid] = { children: [], }; } itemMap[pid].children.push(treeItem); } } return result; } result = arrayToTree1(arr); console.log(result); console.log("========"); function arrayToTree2(items) { const result = []; const itemMap = new Map(); items.map((item, index) => { itemMap.set(item.id, { ...item, children: [] }); }); items.map((item, index) => { const id = item.id; const pid = item.pid; const treeItem = itemMap.get(id); if (pid === 0) { result.push(treeItem); } else { if (!itemMap.get(pid)) { itemMap.set(pid, { children: [] }); } itemMap.set(pid, { ...itemMap.get(pid), children: itemMap.get(pid).children.concat(treeItem), }); } }); return result; } result = arrayToTree2(arr); console.log(result); 

    https://i.v2ex.co/1G1gNIox.png

    中途甚至试着问了问 chat ,它没看出来啥区别敷衍了一下我 TAT 。后面我再想想能不能抢救一下 arrayToTree2

    ===接上一贴:裸辞了,但是单子还没提,总之大小领导都通知了。这里的规矩是通知完点头后才能提单子,这会儿学点自己想学的,边休息变沉淀一下了。

    10 条回复    2023-04-19 13:10:26 +08:00
    shakukansp
        1
    shakukansp  
       2023-04-18 14:44:51 +08:00   1
    if (!itemMap.get(pid)) {
    itemMap.set(pid, { children: [] });
    }

    const item = itermMap.get(pid)
    item.children.push(treeItem)
    devwolf
        2
    devwolf  
    OP
       2023-04-18 14:52:43 +08:00
    @shakukansp 感谢感谢,原来可以这样改,学到了
    shakukansp
        3
    shakukansp  
       2023-04-18 14:59:09 +08:00
    @devwolf arrayToTree1 改的是 itemMap[pid]的 chidren
    你原本的写法 arrayToTree2 改的不是 itemMap.get(pid)的值的 children, 而是改了整个 itemMap.get(pid)的值
    TWorldIsNButThis
        4
    TWorldIsNButThis  
       2023-04-18 15:06:55 +08:00 via iPhone
    啥意思
    map 里存的是对 obj 的引用?
    shakukansp
        5
    shakukansp  
       2023-04-18 15:07:24 +08:00
    简单地说从柜子里面拿出来一个盒子,盒子里面放了另一个盒子,arrayToTree1 是在盒子(itemMap[pid])里面的盒子(children)里加了一个小盒子(treeitem)
    arrayToTree2 是把最外面的大盒子(itemMap.get(pid))整个换掉了,所以你需要做的是不把最外面的盒子换掉,而是先拿出来,再往盒子里面的盒子加小盒子
    devwolf
        6
    devwolf  
    OP
       2023-04-18 15:55:01 +08:00
    @TWorldIsNButThis 就是 #5 的那个巧妙的比喻。
    itemMap[pid] 是个`大盒子`,itemMap[pid].children 是一个`中盒子`,treeitem 是`中盒子`里的`小盒子`。
    需要的是更新`中盒子`里的内容,但是 arrayToTree2 中 itemMap.set 的做法改变了`大盒子`这个角度上来讲,确实 不一样。
    itemMap.set(pid, { ...itemMap.get(pid), children: itemMap.get(pid).children.concat(treeItem)}); 这段写成这样,
    我初衷也是想在拷贝大盒子的同时只更新`中盒子`里的内容,虽然就结果而言并不如我所想的那样,这块我得慢慢悟一下为啥不一样,有成果了就回复你一下(手头来活还在忙别的)
    gitignore
        7
    gitignore  
       2023-04-18 18:05:29 +08:00   1
    // normalize 对象,构建索引便于查找
    const map = {};
    for (const item of arr) {
    item.children = [];
    map[item.id] = item;
    }
    // 将对象添加至父节点
    for (const item of arr) {
    const parent = map[item.pid];
    if (parent) {
    parent.children.push(item);
    }
    }
    // pid 为 0 就是根节点
    return arr.filter(item => item.pid == 0);


    =========
    O(N) 复杂度。

    是我不理解题意,还是考虑不周全,还是什么问题
    devwolf
        8
    devwolf  
    OP
       2023-04-18 22:39:47 +08:00
    完全不记得白天自己看这段代码的时候在想啥了。。。彷佛真在面试现场一样大脑浆糊翻滚,1 楼提醒了也没完全懂用意。
    现在理了一下,确认我之前连 arrayToTree1 都没消化掉。
    结合 shakukansp 的提示,我的理解是:
    [题意] : id 区分每一个值,pid 标记位置,每个 id 按照 pid 来摆放。
    [arrayToTree1] :
    const treeItem = itemMap[id];//treeItem 保存了当前 id 的值

    itemMap[pid].children.push(treeItem);//itemMap 虽然在创建时用 id 作为 key 但可以视作与 id 同值的 pid ,记录一个位置,以此来将 treeItem 放在合适的 children 里

    [arrayToTree2] : 改造后
    const _item = itermMap.get(pid);//这里就是正文里错误代码所欠缺的"盒子"
    _item.children.push(treeItem);//在这个"盒子"里塞东西

    ------------
    天亮我再想想
    devwolf
        9
    devwolf  
    OP
       2023-04-19 11:17:36 +08:00
    一个上午的进展:
    let a = {b:1}, c = a;
    console.log(a);// { b: 1 }
    c.b = 2;
    a = {b:3};
    console.log(a);// { b: 3 }
    console.log(c);// { b: 2 }

    let x = new Map(), z = x;
    x['y'] = '方括号表示法 1';
    x.set('y','set 赋值 1')
    console.log(x.y);// 打印"方括号表示法 1"
    console.log(x.get('y')) // 打印"set 赋值 1"

    阶段总结:
    原本以为是“换了一个写法”的"改引用的值还是改引用" 这类问题。
    现在发现 Map 对象用 方括号 /点号表示法 存的位置和 se 不一样
    devwolf
        10
    devwolf  
    OP
       2023-04-19 13:10:26 +08:00
    @gitignore 没啥问题啊,你这个对我而言可读性还更友好了。

    @TWorldIsNButThis 不是这个意思,标题我是在未理解题意的时候起的,现在看来和标题关系不大了
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2352 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 15:45 PVG 23:45 LAX 08:45 JFK 11:45
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86