Estoy trabajando en una visualización de d3-force , que requiere datos en una forma específica. Tengo una serie de objetos, cada uno con una serie de etiquetas.
nodes = [ { name: "post1", tag_list: ["activity", "online"] }, { name: "post2", tag_list: ["workshop", "online"] }, { name: "post3", tag_list: ["english", "workshop"] }, ... ]Para establecer conexiones entre datos, necesito definir explícitamente una matriz de enlaces:
links = [ { source: 'post1', target: 'post2' }, { source: 'post2', target: 'post3' }, ... ]No hay diferencia en la similitud entre los enlaces: todas las relaciones son lineales y tienen la misma "agencia" . Idealmente, los datos idénticos deberían filtrarse para evitar líneas duplicadas.
¿Cómo puedo generar una matriz de enlaces de la forma mencionada anteriormente a partir de las matrices tag_list ?
Aquí hay un ejemplo de la estructura de datos requerida.
--
Un poco de contexto: estoy tratando de visualizar superposiciones temáticas entre las páginas del blog. Todas las páginas tienen una serie de etiquetas para describirlas ( tag_list ). Deseo conectar todas las etiquetas dentro del gráfico. Dado que d3 requiere referencias detalladas para dibujar enlaces (consulte el enlace a continuación), necesito calcularlas a partir de las listas de etiquetas a las que tengo acceso.
Puede recopilar cada etiqueta y, para cada etiqueta, recopilar los distintos nombres (en un conjunto). Cuando una etiqueta de este tipo ya tiene nombres asociados, repítalos y combínelos con el nombre "actual", colocando el nombre léxicamente más pequeño como primer miembro del par. Guarda este par en un mapa de Sets, para que sean únicos.
Aquí hay una implementación:
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);Puede utilizar el enfoque de agrupación hash. Primero haga un objeto donde las claves sean hashes de los enlaces, y luego use solo los valores como resultado.
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}