从标签计算关系数组

Computing array of relationships from tags

我正在研究 d3-force visualisation,这需要 特定形状的数据。我有一组对象,每个对象都有一组标签。

nodes = [
  { name: "post1", tag_list: ["activity", "online"] },
  { name: "post2", tag_list: ["workshop", "online"] },
  { name: "post3", tag_list: ["english", "workshop"] },
  ...
]

要在数据之间建立连接,我需要显式定义一个 link 数组:

links = [
  { 
    source: 'post1', 
    target: 'post2' 
  },
  { 
    source: 'post2', 
    target: 'post3' 
  },
  ...
]

link 之间的相似性没有差异 - 所有关系都是线性的并且具有相同的 “代理”。最好过滤相同的数据以防止重复行。

我如何从 tag_list 数组中生成前面提到的形状的 link 数组?

Here's an example of the required data structure.

--

一些上下文:我正在尝试可视化博客页面之间的主题重叠。所有页面都有一组标签来描述它们 (tag_list)。我希望连接图中的所有标签。由于 d3 需要冗长的引用来绘制 links(参见下面的 link),我需要从我可以访问的标签列表中计算这些。

您可以使用散列分组方法。首先创建一个对象,其中键是链接的哈希值,然后仅使用值作为结果。

const nodes = [
  { name: "post1", tag_list: ["activity", "online"] },
  { name: "post2", tag_list: ["workshop", "online"] },
  { name: "post3", tag_list: ["online"] },
  { name: "post4", tag_list: ["workshop"] },
  { name: "post5", tag_list: ["lonely"] },
];

const hasIntersection = (arrA, arrB) => arrA.some((el) => arrB.includes(el));

const groupedByHash = nodes.reduce((acc, targetNode) => {
  const commonNodes = nodes
    .filter(({ tag_list }) => hasIntersection(tag_list, targetNode.tag_list))
    .filter(({ name }) => name !== targetNode.name);

  if (commonNodes.length < 1) return acc;
  
  const commonLinks = commonNodes.reduce((acc, { name }) => {
    const [source, target] = [name, targetNode.name].sort();
    const hash = [source, target].join('---');
    acc[hash] = { source, target };
    return acc;
  }, {});
  
  return { ...acc, ...commonLinks };
}, {});

const result = Object.values(groupedByHash);


console.log(result);
.as-console-wrapper{min-height: 100%!important; top: 0}

您可以收集每个标签,并为每个标签收集不同的名称(在一个集合中)。当这样的标签已经有与之关联的名称时,迭代这些名称并将其与“当前”名称配对,将词法较小的名称放在第一个 pair-member。将这对存储在 Set 的映射中,以便它们是唯一的。

这是一个实现:

let nodes = [
  { name: "post1", tag_list: ["activity", "online"] },
  { name: "post2", tag_list: ["workshop", "online"] },
  { name: "post3", tag_list: ["english", "workshop"] },
];

let tags = {};
let pairs = {};
let result = [];
for (let {name, tag_list} of nodes) {
    for (let tag of tag_list) {
        for (let other of tags[tag] ??= new Set) {
            let [source, target] = [name, other].sort();
            if (!(pairs[source] ??= new Set).has(target)) {
                pairs[source].add(target);
                result.push({source, target});
            }
        }
        tags[tag].add(name);
    }
}

console.log(result);