Quiero generar un árbol de matriz de objetos con diferentes niveles y posiciones. En mi opinión, parentId puede crear el nivel como en "niños". La posición puede ordenar los elementos.
¿Alguien puede ayudarme cómo puedo lograr esto?
Recibo los siguientes datos de la API:
[ { label: "Level one 1", id: 1, parentId: null, position: 0}, { label: "Level two 1-1", id: 4, parentId: 1, position: 0}, { label: "Level three 1-1-1", id: 9, parentId: 4, position: 1}, ]Aquí hay un ejemplo de cómo quiero los datos al final:
const dataSource = ref([ { id: 1, position: 0, parentId: null, label: 'Level one 1', children: [ { id: 4, position: 0, parentId: 1, label: 'Level two 1-1', children: [ { id: 9, parentId: 4, position: 0, label: 'Level three 1-1-1', }, { id: 10, parentId: 4, position: 1, label: 'Level three 1-1-2', }, ], }, ], }, { id: 2, position: 1, parentId: null, label: 'Level one 2', children: [ { id: 5, position: 0, parentId: 2, label: 'Level two 2-1', }, { id: 6, position: 1, parentId: 2, label: 'Level two 2-2', }, ], }, { id: 3, position: 2, parentId: null, label: 'Level one 3', children: [ { id: 7, position: 0, parentId: 3, label: 'Level two 3-1', }, { id: 8, position: 1, parentId: 3, label: 'Level two 3-2', }, ], }, ])para esto, puede combinar el método de map para redefinir el elemento en su matriz y filter para obtener solo el elemento secundario de un objeto principal
var data = [ { label: "Level one 1", id: 1, parentId: null, position: 0}, { label: "Level two 1-1", id: 4, parentId: 1, position: 0}, { label: "Level three 1-1-1", id: 9, parentId: 4, position: 1}, ]; var result = data.map(elem => { elem.children = data.filter(item => item.parentId === elem.id); return elem; }); console.log(result);Podría adoptar un enfoque de bucle único con un objeto como referencia para cada nodo.
const getTree = (data, root) => { const t = {}; data.forEach(o => ((t[o.parentId] ??= {}).children ??= []).push(Object.assign(t[o.id] ??= {}, o))); return t[root].children; }, data = [{ label: "Level one 1", id: 1, parentId: null, position: 0 }, { label: "Level two 1-1", id: 4, parentId: 1, position: 0 }, { label: "Level three 1-1-1", id: 9, parentId: 4, position: 1 }], tree = getTree(data, null); console.log(tree); .as-console-wrapper { max-height: 100% !important; top: 0; }Esta solución primero crea una copia de cada objeto y la almacena en una instancia de Map. Agrego manualmente la clave null con valor { children: [] } , para que podamos manejar/encontrar el objeto raíz fácilmente.
Después de crear la instancia del Mapa, recorro cada registro. Obtenga tanto la copia del registro en sí como el padre. Luego asigne parent.children a una matriz si no está presente. Finalmente, asigno el record como hijo de parent en función de su position .
function recordsToTree(records) { const lookup = new Map(records.map(({ ...record }) => [record.id, record])); lookup.set(null, { children: [] }); for (const { id, parentId, position } of records) { const record = lookup.get(id); const parent = lookup.get(parentId); parent.children ||= []; parent.children[position] = record; } return lookup.get(null).children; } console.log( recordsToTree([ { label: "Level three 1-1-2", id: 3, parentId: 4, position: 1 }, { label: "Level one 1", id: 1, parentId: null, position: 0 }, { label: "Level three 1-1-1", id: 9, parentId: 4, position: 0 }, { label: "Level two 1-1", id: 4, parentId: 1, position: 0 }, ]) ); Si la position no refleja el índice de un elemento secundario, puede usar parent.children.push(record) en lugar de parent.children[position] = record .