I am currently making a tree view, where there will be folders and subfolders. The code is as such from my json file:
[
{
"name": "Knowledge Base",
"files": [
"knowledge-base.pdf",
"hello-word.pdf"
],
"folders": [
{
"name": "Documents",
"files": [
"file1.pdf",
"file2.pdf",
"file3.pdf"
],
"folders": [
{
"name": "Important Documents",
"files": [
"I like trains",
"Why",
"OMG NOOOO"
],
"folders": [
{
"name": "Hello World",
"files": [
"Hell no"
]
}
]
},
{
"name": "My secrets",
"files": [
"Pay",
"I dont like my boss",
"Hobbies"
]
}
]
},
{
"name": "Images",
"files": [
"image1.png",
"image2.png",
"image3.png",
"image4.png",
"image5.png"
],
"folders": ""
},
{
"name": "Important",
"files": [
"confidential.pdf",
"important.pdf"
],
"folders": ""
}
]
},
{
"name": "Downloads",
"files": [
"download1.pdf",
"download2.pdf",
"download3.pdf"
],
"folders": ""
},
{
"name": "Favourites",
"files": [
"favourite1.pdf",
"favourite2.pdf",
"favourite3.pdf",
"favourite4.pdf"
],
"folders": ""
}
]
A new folder is denoted with a new object {}, which consists of its name, files and folders within it, if any.
I would like to flatten the dictionary such that it outputs all files (with a file is denoted by a . and a folder is denoted by a >:
For example, for the documents folder:
- Knowledge Base>Documents.file1.pdf
- Knowledge Base>Documents.file2.pdf
- Knowledge Base>Documents.file3.pdf
- Knowledge Base>Documents>Important Documents.I like trains
- Knowledge Base>Documents>Important Documents.Why
- Knowledge Base>Documents>Important Documents.OMG NOOOO
- Knowledge Base>Documents>Important Documents>Hello World.Hell no
- Knowledge Base>Documents>My Secrets.I dont like my boss
- Knowledge Base>Documents>My Secrets.Hobbies
CodePudding user response:
Recursive function is to the resqueue.
The idea behind recursive function is that it accepts an object as parameter and if a child of that object contains folders, loop through array of these folders and send each folder object back to the same function.
const data = [
{
"name": "Knowledge Base",
"files": [
"knowledge-base.pdf",
"hello-word.pdf"
],
"folders": [
{
"name": "Documents",
"files": [
"file1.pdf",
"file2.pdf",
"file3.pdf"
],
"folders": [
{
"name": "Important Documents",
"files": [
"I like trains",
"Why",
"OMG NOOOO"
],
"folders": [
{
"name": "Hello World",
"files": [
"Hell no"
]
}
]
},
{
"name": "My secrets",
"files": [
"Pay",
"I dont like my boss",
"Hobbies"
]
}
]
},
{
"name": "Images",
"files": [
"image1.png",
"image2.png",
"image3.png",
"image4.png",
"image5.png"
],
"folders": ""
},
{
"name": "Important",
"files": [
"confidential.pdf",
"important.pdf"
],
"folders": ""
}
]
},
{
"name": "Downloads",
"files": [
"download1.pdf",
"download2.pdf",
"download3.pdf"
],
"folders": ""
},
{
"name": "Favourites",
"files": [
"favourite1.pdf",
"favourite2.pdf",
"favourite3.pdf",
"favourite4.pdf"
],
"folders": ""
}
];
function flatten(obj, parent = "")
{
parent = obj.name ">"; //append current folder name
let result = obj.files ? obj.files.map(file => parent file) : [];//add files
if (Array.isArray(obj.folders))
result = result.concat(...obj.folders.map(folder => flatten(folder, parent))); //recursivly call flatten for next subfolder
return result;
}
const dataFlat = data.reduce((a,b) => (a.push(...flatten(b)), a), []);
console.log(dataFlat);
.as-console-wrapper{top:0;max-height:unset!important;overflow:auto!important;}
CodePudding user response:
For that you need to do a recursive identifying when it is an array, a folder or a file.
const treeView = [
{
name: "Knowledge Base",
files: [
"knowledge-base.pdf",
"hello-word.pdf"
],
folders: [
{
name: "Documents",
files: [
"file1.pdf",
"file2.pdf",
"file3.pdf"
],
folders: [
{
name: "Important Documents",
files: [
"I like trains",
"Why",
"OMG NOOOO"
],
folders: [
{
name: "Hello World",
files: [
"Hell no"
]
}
]
},
{
name: "My secrets",
files: [
"Pay",
"I dont like my boss",
"Hobbies"
]
}
]
},
{
name: "Images",
files: [
"image1.png",
"image2.png",
"image3.png",
"image4.png",
"image5.png"
],
folders: ""
},
{
name: "Important",
files: [
"confidential.pdf",
"important.pdf"
],
folders: ""
}
]
},
{
name: "Downloads",
files: [
"download1.pdf",
"download2.pdf",
"download3.pdf"
],
folders: ""
},
{
name: "Favourites",
files: [
"favourite1.pdf",
"favourite2.pdf",
"favourite3.pdf",
"favourite4.pdf"
],
folders: ""
}
]
function handleObj(obj, type, path = '') {
const result = []
if (Array.isArray(obj)) { // recursive on arrays
for (const thisObj of obj) {
result.push(handleObj(thisObj, type, path))
}
} else {
type = type || getType(obj)
if (type === 'folder') { // recursive on folders
const {
name,
files,
folders
} = obj
path = path ? `${path}>${name}` : name
if (files && files.length) {
result.push(handleObj(files, 'file', path))
}
if (folders && folders.length) {
result.push(handleObj(folders, 'folder', path))
}
} else if (type === 'file') {
const filename = obj
if (path) {
result.push(`${path}.${filename}`)
} else {
result.push(`${filename}`)
}
}
}
return result.join('\n')
}
function getType(obj) {
const {
name,
files,
folders
} = obj
if (name !== undefined && files !== undefined && folders !== undefined) {
return 'folder'
}
return 'file'
}
console.log(handleObj(treeView))
CodePudding user response:
You can use a basic recusrive function like this:
const tree = [{
"name": "Knowledge Base",
"files": [
"knowledge-base.pdf",
"hello-word.pdf"
],
"folders": [{
"name": "Documents",
"files": [
"file1.pdf",
"file2.pdf",
"file3.pdf"
],
"folders": [{
"name": "Important Documents",
"files": [
"I like trains",
"Why",
"OMG NOOOO"
],
"folders": [{
"name": "Hello World",
"files": [
"Hell no"
]
}]
},
{
"name": "My secrets",
"files": [
"Pay",
"I dont like my boss",
"Hobbies"
]
}
]
},
{
"name": "Images",
"files": [
"image1.png",
"image2.png",
"image3.png",
"image4.png",
"image5.png"
],
"folders": ""
},
{
"name": "Important",
"files": [
"confidential.pdf",
"important.pdf"
],
"folders": ""
}
]
},
{
"name": "Downloads",
"files": [
"download1.pdf",
"download2.pdf",
"download3.pdf"
],
"folders": ""
},
{
"name": "Favourites",
"files": [
"favourite1.pdf",
"favourite2.pdf",
"favourite3.pdf",
"favourite4.pdf"
],
"folders": ""
}
]
var result = []
function rec(folders, acc) {
if (folders) {
folders.forEach(folder => {
const newAcc = !!acc ? `${acc}>${folder.name}` : `${folder.name}`
if (folder.files) {
const newFiles = folder.files.map(file => `${newAcc}.${file}`)
result = [...result, ...newFiles]
}
if (folder.folders) {
rec(folder.folders, newAcc)
}
})
}
}
rec(tree, '')
console.log(result)