javascript 基于节点层次结构创建面包屑

qcbq4gxm  于 2023-02-11  发布在  Java
关注(0)|答案(3)|浏览(202)

节点层次结构如下所示:

{
       "nodes":[
          {
             "assetId":"cfe-3a2b-47e7-b7e9-e2e090ca0d34",
             "assetName":"IRCTC",
             "assetType":"Company"
          },
          {
             "assetId":"32d9-05b8-4293-af55-2ee4617c6ffe",
             "assetName":"Northern Railway Fleet",
             "assetType":"Fleet"
          },
          {
             "assetId":"15-b76c-426c-a272-6485359c5836",
             "assetName":"Vande Bharat Express",
             "assetType":"Train"
          }
       ],
       "edges":[
          {
             "source":"cfe-3a2b-47e7-b7e9-e2e090ca0d34",
             "destination":"32d9-05b8-4293-af55-2ee4617c6ffe",
             "relation":"HAS"
          },
          {
             "source":"32d9-05b8-4293-af55-2ee4617c6ffe",
             "destination":"15-b76c-426c-a272-6485359c5836",
             "relation": "HAS"
          }
       ]
    }

基本上,节点包含一组资产列表,边包含它们的Map或关系。我们需要先遍历节点,然后创建一个名为
创建面包屑(“15-b76 c-426 c-a272 - 6485359 c5836”);
它应该在边缘对象中检查该节点ID并检索其父节点。

Breadcrumb would be:

"IRCTC > Northern Railway Fleet > Vande Bharat Express"
0vvn1miw

0vvn1miw1#

可以通过创建中间对象nodeIdToNamenodeIdToParentId来实现,以便在while循环中轻松查找:

const hierarchy = {
  nodes: [ { assetId:"cfe-3a2b-47e7-b7e9-e2e090ca0d34", assetName:"IRCTC", assetType:"Company" }, { assetId:"32d9-05b8-4293-af55-2ee4617c6ffe", assetName:"Northern Railway Fleet", assetType:"Fleet" }, { assetId:"15-b76c-426c-a272-6485359c5836", assetName:"Vande Bharat Express", assetType:"Train" } ],
  edges: [ { source:"cfe-3a2b-47e7-b7e9-e2e090ca0d34", destination:"32d9-05b8-4293-af55-2ee4617c6ffe", relation:"HAS" }, { source:"32d9-05b8-4293-af55-2ee4617c6ffe", destination:"15-b76c-426c-a272-6485359c5836", relation: "HAS" } ]
};

const nodeIdToName = hierarchy.nodes.reduce((acc, obj) => {
  acc[obj.assetId] = obj.assetName;
  return acc;
}, {});
const nodeIdToParentId = hierarchy.edges.reduce((acc, obj) => {
  acc[obj.destination] = obj.source;
  return acc;
}, {});

function createBreadcrumbs(id) {
  let breadcrumb = [];
  while(nodeIdToName[id]) {
    breadcrumb.push(nodeIdToName[id]);
    id = nodeIdToParentId[id];
  }
  return breadcrumb.reverse().join(' > ');
}

const breadcrumb = createBreadcrumbs("15-b76c-426c-a272-6485359c5836");

console.log({
  nodeIdToName,
  nodeIdToParentId,
  breadcrumb
});

输出:

{
  "nodeIdToName": {
    "cfe-3a2b-47e7-b7e9-e2e090ca0d34": "IRCTC",
    "32d9-05b8-4293-af55-2ee4617c6ffe": "Northern Railway Fleet",
    "15-b76c-426c-a272-6485359c5836": "Vande Bharat Express"
  },
  "nodeIdToParentId": {
    "32d9-05b8-4293-af55-2ee4617c6ffe": "cfe-3a2b-47e7-b7e9-e2e090ca0d34",
    "15-b76c-426c-a272-6485359c5836": "32d9-05b8-4293-af55-2ee4617c6ffe"
  },
  "breadcrumb": "IRCTC > Northern Railway Fleet > Vande Bharat Express"
}

注:在输出中添加nodeIdToNamenodeIdToParentId仅用于说明

9rygscc1

9rygscc12#

  • 你可以创建2个Map对象,一个Map每个节点的assetId-〉assetName,另一个Map对象Map每条边的destination-〉到它的source
  • 创建一个接受id的函数,获取当前id的source和节点名。
  • 如果source不为空,则递归调用该函数并在末尾追加当前crumb。否则,返回,current crumb
const input = {nodes:[{assetId:"cfe-3a2b-47e7-b7e9-e2e090ca0d34",assetName:"IRCTC",assetType:"Company"},{assetId:"32d9-05b8-4293-af55-2ee4617c6ffe",assetName:"Northern Railway Fleet",assetType:"Fleet"},{assetId:"15-b76c-426c-a272-6485359c5836",assetName:"Vande Bharat Express",assetType:"Train"}],edges:[{source:"cfe-3a2b-47e7-b7e9-e2e090ca0d34",destination:"32d9-05b8-4293-af55-2ee4617c6ffe",relation:"HAS"},{source:"32d9-05b8-4293-af55-2ee4617c6ffe",destination:"15-b76c-426c-a272-6485359c5836",relation:"HAS"}]},
      nodeMap = new Map ( input.nodes.map(o => [o.assetId, o.assetName]) ),
      edgeMap = new Map ( input.edges.map(o => [o.destination, o.source]) )

function getCrumb(id) {
  const crumb = nodeMap.get(id),
        source = edgeMap.get(id);
        
  return source 
            ? [getCrumb(source), crumb].join(' > ')
            : crumb
}

console.log( getCrumb("15-b76c-426c-a272-6485359c5836") )
console.log( getCrumb("32d9-05b8-4293-af55-2ee4617c6ffe") )
efzxgjgh

efzxgjgh3#

我将提出一个解决方案,它使用与这个问题的其他答案相同的惯用数据结构:associative array-但是,此答案侧重于使用函数式编程来获得解决方案:
第一步是从初始输入生成doubly-linked list节点的Map,这将为您提供解决所描述的问题所需的所有关系数据,并从您提供的示例输入中获得任何其他类型的关系洞察力:

function linkAssets (graph) {
  const map = new Map();

  for (const asset of graph.nodes) {
    map.set(asset.assetId, {value: asset});
  }

  for (const edge of graph.edges) {
    if (edge.relation === "HAS") {
      const previous = map.get(edge.source);
      const next = map.get(edge.destination);

      if (previous && next) {
        previous.next = next;
        next.previous = previous;
      }
    }
  }

  return map;
}

然后,您可以使用链接列表对象的Map来构建您的面包屑路径:

function createBreadcrumbs (
  graph,
  lastAssetId,
  {
    delimiter = " > ",
    transformFn = (asset) => asset.assetName,
  } = {},
) {
  const map = linkAssets(graph);
  const assetPath = [];
  let node = map.get(lastAssetId);

  while (node) {
    assetPath.unshift(transformFn(node.value));
    node = node.previous;
  }

  return assetPath.join(delimiter);
}

使用它的过程如下所示:

const result = createBreadcrumbs(input, "15-b76c-426c-a272-6485359c5836");
console.log(result); // "IRCTC > Northern Railway Fleet > Vande Bharat Express"

还可以自定义输出:

const result2 = createBreadcrumbs(input, "15-b76c-426c-a272-6485359c5836", {
  delimiter: " ➡️ ",
  transformFn: a => `${a.assetName} (${a.assetType})`,
});

console.log(result2); // "IRCTC (Company) ➡️ Northern Railway Fleet (Fleet) ➡️ Vande Bharat Express (Train)"

下面是一个工作代码片段示例,其中包含上面的代码和您输入的问题:

"use strict";

function linkAssets (graph) {
  const map = new Map();

  for (const asset of graph.nodes) {
    map.set(asset.assetId, {value: asset});
  }

  for (const edge of graph.edges) {
    if (edge.relation === "HAS") {
      const previous = map.get(edge.source);
      const next = map.get(edge.destination);

      if (previous && next) {
        previous.next = next;
        next.previous = previous;
      }
    }
  }

  return map;
}

function createBreadcrumbs (
  graph,
  lastAssetId,
  {
    delimiter = " > ",
    transformFn = (asset) => asset.assetName,
  } = {},
) {
  const map = linkAssets(graph);
  const assetPath = [];
  let node = map.get(lastAssetId);

  while (node) {
    assetPath.unshift(transformFn(node.value));
    node = node.previous;
  }

  return assetPath.join(delimiter);
}

const input = {"nodes":[{"assetId":"cfe-3a2b-47e7-b7e9-e2e090ca0d34","assetName":"IRCTC","assetType":"Company"},{"assetId":"32d9-05b8-4293-af55-2ee4617c6ffe","assetName":"Northern Railway Fleet","assetType":"Fleet"},{"assetId":"15-b76c-426c-a272-6485359c5836","assetName":"Vande Bharat Express","assetType":"Train"}],"edges":[{"source":"cfe-3a2b-47e7-b7e9-e2e090ca0d34","destination":"32d9-05b8-4293-af55-2ee4617c6ffe","relation":"HAS"},{"source":"32d9-05b8-4293-af55-2ee4617c6ffe","destination":"15-b76c-426c-a272-6485359c5836","relation":"HAS"}]};

const result = createBreadcrumbs(input, "15-b76c-426c-a272-6485359c5836");
console.log(result);

const result2 = createBreadcrumbs(input, "15-b76c-426c-a272-6485359c5836", {
  delimiter: " ➡️ ",
  transformFn: a => `${a.assetName} (${a.assetType})`,
});

console.log(result2);

TypeScriptPlayground中的代码

相关问题