Digamos que tengo las siguientes cadenas:
"archivos/fotos/foo.png"
"archivos/videos/película.mov"
y quiero convertirlos en el siguiente objeto:
{ name: "files" children: [{ name: "photos", children: [{ name: "foo.png", id: "files/photos/foo.png" }] },{ name: "videos", children: [{ name: "movie.mov", id: "files/videos/movie.mov" }] }] }¿Cuál sería el mejor enfoque para hacerlo? He intentado escribir algunas funciones recursivas, sin embargo, admito que estoy luchando en este momento.
Aquí hay un fragmento rápido con una posible solución. Utiliza bucles anidados, el exterior divide cada ruta por el delimitador y extrae pop() la parte del archivo de la matriz. El interior itera las partes de la ruta y construye la jerarquía reasignando branch en cada iteración. Finalmente, la parte del file de la ruta se agrega a la branch más profunda.
const data = [ 'files/photos/foo.png', 'files/photos/bar.png', 'files/videos/movie.mov', 'docs/photos/sd.jpg' ]; const tree = { root: {} } for (const path of data) { const parts = path.split('/'); const file = parts.pop(); let branch = tree, partPath = ''; for (const part of parts) { partPath += `${part}/`; if (partPath === `${part}/`) { tree.root[partPath] = (tree[partPath] ??= { name: part, children: [] }); } else if (tree[partPath] === undefined) { tree[partPath] = { name: part, children: [] }; branch.children.push(tree[partPath]); } branch = tree[partPath]; } branch.children.push({ name: file, id: path }); } const result = Object.values(tree.root) console.log(JSON.stringify(result, null, 2)) .as-console-wrapper { max-height: 100% !important; top: 0; } .as-console-row::after { display: none !important; }O como una función.
function mergeAssets(assets) { const tree = { root: {} } for (const path of data) { const parts = path.split('/'); const file = parts.pop(); let branch = tree, partPath = ''; for (const part of parts) { partPath += `${part}/`; if (partPath === `${part}/`) { tree.root[partPath] = (tree[partPath] ??= { name: part, children: [] }); } else if (tree[partPath] === undefined) { tree[partPath] = { name: part, children: [] }; branch.children.push(tree[partPath]); } branch = tree[partPath]; } branch.children.push({ name: file, id: path }); } return { name: "assets", children: Object.values(tree.root) } } const data = [ 'files/photos/foo.png', 'files/photos/bar.png', 'files/videos/movie.mov', 'docs/photos/sd.jpg' ]; const result = mergeAssets(data); console.log(JSON.stringify(result, null, 2))Pude encontrar una solución usando una función recursiva. Si otros tienen algún consejo sobre cómo mejorar esto, me encantaría escucharlo.
function mergeObjects(parentArray,path,originalName){ if(originalName === undefined){ originalName = path; } const parts = path.split("/"); var nextPart = ""; parts.forEach((part, index) => index > 0 ? nextPart += (nextPart !== "" ? "/" : "") + part : null); //does the parentArray contain a child with our name? const indexOfChild = parentArray.findIndex(child => child.name === parts[0]); if(indexOfChild === -1){ //this item does not exist if(parts.length > 1){ var index = parentArray.push({ name: parts[0], children : [] }) - 1; mergeObjects(parentArray[index].children,nextPart,originalName); }else{ parentArray.push({ name: parts[0], id : originalName }); } }else{ //this item already exists if(parts.length > 1){ mergeObjects(parentArray[indexOfChild].children,nextPart,originalName); } } }Y la función se llama con lo siguiente:
function mergeAssets(assets){ var obj = { name: "assets", children: [] }; assets.forEach(asset => mergeObjects(obj.children,asset)); return obj; }