JS新手求助:将邻接矩阵转换为类JSON嵌套父子结构
邻接矩阵转指定父子对象结构问题
需求
我是JavaScript新手,需要把带区域信息的二维邻接矩阵数组转换成指定的类JSON父子对象结构,因为只有父子层级(无祖父节点),不需要递归实现。
原始数据
原始邻接矩阵(仅关注链接存在性,忽略权重):
const exampleRawLinks = [ { n1: NaN, n2: 1.2, n3: NaN, n4: 1.3 }, { n1: NaN, n2: NaN, n3: NaN, n4: 1.4 }, { n1: NaN, n2: 1.5, n3: NaN, n4: 1.4 }, { n1: NaN, n2: NaN, n3: 1.3, n4: NaN }, ];
补充区域和节点名称后的数据:
const nodeLinks = [ { region: 1, node: "n1", n1: NaN, n2: 1.2, n3: NaN, n4: 1.3 }, { region: 1, node: "n2", n1: NaN, n2: NaN, n3: NaN, n4: 1.4 }, { region: 2, node: "n3", n1: NaN, n2: 1.5, n3: NaN, n4: 1.4 }, { region: 3, node: "n4", n1: NaN, n2: NaN, n3: 1.3, n4: NaN }, ];
期望结果
转换后的结构(id和group对应区域,targets为当前节点有链接的节点名):
const dataFinal = { children: [ { id: 1, children: [ { id: "n1", group: 1, targets: ["n2", "n4"] }, { id: "n2", group: 1, targets: ["n4"] } ] }, { id: 2, children: [ { id: "n3", group: 2, targets: ["n2", "n4"] } ] }, { id: 3, children: [ { id: "n4", group: 3, targets: ["n3"] } ] } ] };
(注:原期望结果存在几处笔误,已修正,确保与原始数据对应)
尝试过程及问题
我试过用d3.groups()按区域分组,也写了一段代码,但targets数组始终为空,怀疑是slice的范围错误,当前代码:
dataFinal = Object.entries(nodeLinks) .map(d => ({ id: d[1].region, children: [({ id: d[1].node, group: d[1].region, targets: Object.keys(Array(d[1]).slice(2,-1).map(obj => _.omitBy(obj, _.isNull))) })] }));
解决方案
步骤1:按区域分组
用Array.reduce()先把nodeLinks按region分组,得到以区域为键、节点数组为值的对象:
const groupedByRegion = nodeLinks.reduce((acc, item) => { if (!acc[item.region]) { acc[item.region] = []; } acc[item.region].push(item); return acc; }, {});
步骤2:转换每个节点并生成targets
对每个分组里的节点,过滤出除region和node外的属性,判断值是否为有效数值(不是NaN),收集这些属性名作为targets:
const dataFinal = { children: Object.entries(groupedByRegion).map(([regionId, nodes]) => ({ id: Number(regionId), children: nodes.map(node => { // 生成targets:筛选出值不是NaN的节点名 const targets = Object.keys(node) .filter(key => !['region', 'node'].includes(key)) .filter(key => !Number.isNaN(node[key])); return { id: node.node, group: node.region, targets: targets }; }) })) };
完整代码
const nodeLinks = [ { region: 1, node: "n1", n1: NaN, n2: 1.2, n3: NaN, n4: 1.3 }, { region: 1, node: "n2", n1: NaN, n2: NaN, n3: NaN, n4: 1.4 }, { region: 2, node: "n3", n1: NaN, n2: 1.5, n3: NaN, n4: 1.4 }, { region: 3, node: "n4", n1: NaN, n2: NaN, n3: 1.3, n4: NaN }, ]; // 按区域分组 const groupedByRegion = nodeLinks.reduce((acc, item) => { if (!acc[item.region]) { acc[item.region] = []; } acc[item.region].push(item); return acc; }, {}); // 转换为目标结构 const dataFinal = { children: Object.entries(groupedByRegion).map(([regionId, nodes]) => ({ id: Number(regionId), children: nodes.map(node => { const targets = Object.keys(node) .filter(key => !['region', 'node'].includes(key)) .filter(key => !Number.isNaN(node[key])); return { id: node.node, group: node.region, targets: targets }; }) })) }; console.log(dataFinal);
代码说明
- 用
reduce分组更直观,无需额外依赖(如果已使用d3,也可以用d3.groups(nodeLinks, d => d.region)后转换结构) - 生成
targets时直接过滤无关字段并判断数值有效性,避免了原代码中Array(d[1])这类错误操作导致的slice失效问题 - 修正了原期望结果的笔误,确保输出与原始数据完全对应
内容的提问来源于stack exchange,提问作者Skyehawk
相关产品推荐
相关产品推荐

