从标签计算关系数组
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);
我正在研究 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);