Flattening an array of objects based on specific keys - javascript

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

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)

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))

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;}

Related

how to sort array of object in js by property i.ecategoryname' in my dataset in alphabetical order using mergesort

Here is the list of data that should be sorted in alphabetical based of categoryName
value using merger sort
const filteritem = [
{
"categoryName": "admission",
"rows": [
{
"uploaddate": "8/8/2022",
"title": "binoddocs",
"view": "https://firebasestorage.googleapis.com/v0/b/auth",
"fullname": "bruno",
"id": "B8QsXYVFH8fHt3PrBYUp"
}
]
},
{
"categoryName": "officialdocument",
"rows":
{
"file": null,
"uploadedby": "bruno",
"uploaddate": "6/27/2022",
"title": "sudhikchaadmission",
"view": "https://firebasestorage.googleapis.com/v0/b/auth",
"id": "Z27GLizWnYTJvLQyYRQt"
},
{
"view": "https://firebasestorage.googleapis.com/v0/b/auth",
"uploadedby":"bruno",
"uploaddate":"6/27/2022",
"title":"ankitadmission",
"file":null,
"id":"rmcbUrg9TpFhQh5RLqva"
}
]
},
{
"categoryName":"syallabus",
"rows": [
{
"fullname":"bruno",
"view":"https://firebasestorage.googleapis.com/v0/b/auth",
"title":"sudhir",
"uploaddate":"8/15/2022",
"id":"hi7QEOlBzzVLZ1QHYqlk"
}
]
},
{
"categoryName":"Binodkhatricv",
"rows": [
{
"title":"binodtry",
"fullname":"bruno",
"uploaddate":"8/15/2022",
"view":"https://firebasestorage.googleapis.com/v0/b/auth",
"id":"o4EtP1xkbWMk1icp4uNH"
}
]
i can use filter and includes method to sort.. but i have to implement some types of algorithm in my project like{mergersort ,bubblesort,depthsearch etc}but for now i need to use mergesort***
The final result should be like this i have not included all the property inside the object here i think you got it ..
filteritem=[
{categoryName:"admission"...},
{cateogryName:"Binodkhatricv"..},
{categoryName:"officialdocument"...},
{categoryName:"syallabus"...}
]```
You can use sort I guess it's do want to try to do :
const filteritem = [
{
"categoryName": "admission",
"rows": [
{
"uploaddate": "8/8/2022",
"title": "binoddocs",
"view": "https://firebasestorage.googleapis.com/v0/b/auth",
"fullname": "bruno",
"id": "B8QsXYVFH8fHt3PrBYUp"
}
]
},
{
"categoryName": "officialdocument",
"rows":
[{
"file": null,
"uploadedby": "bruno",
"uploaddate": "6/27/2022",
"title": "sudhikchaadmission",
"view": "https://firebasestorage.googleapis.com/v0/b/auth",
"id": "Z27GLizWnYTJvLQyYRQt"
},
{
"view": "https://firebasestorage.googleapis.com/v0/b/auth",
"uploadedby":"bruno",
"uploaddate":"6/27/2022",
"title":"ankitadmission",
"file":null,
"id":"rmcbUrg9TpFhQh5RLqva"
}
]
},
{
"categoryName":"syallabus",
"rows": [
{
"fullname":"bruno",
"view":"https://firebasestorage.googleapis.com/v0/b/auth",
"title":"sudhir",
"uploaddate":"8/15/2022",
"id":"hi7QEOlBzzVLZ1QHYqlk"
}
]
},
{
"categoryName":"Binodkhatricv",
"rows": [
{
"title":"binodtry",
"fullname":"bruno",
"uploaddate":"8/15/2022",
"view":"https://firebasestorage.googleapis.com/v0/b/auth",
"id":"o4EtP1xkbWMk1icp4uNH"
}
]
}];
let sorted = filteritem.sort((a, b) => (a < b ? -1 : 1))
console.log(sorted)
You need to use localeCompare to sort the string, but after toLowerCase to ignore case sensitivity.
const filteritem = [
{
"categoryName": "admission",
"rows": [
{
"uploaddate": "8/8/2022",
"title": "binoddocs",
"view": "https://firebasestorage.googleapis.com/v0/b/auth",
"fullname": "bruno",
"id": "B8QsXYVFH8fHt3PrBYUp"
}
]
},
{
"categoryName": "officialdocument",
"rows": [
{
"file": null,
"uploadedby": "bruno",
"uploaddate": "6/27/2022",
"title": "sudhikchaadmission",
"view": "https://firebasestorage.googleapis.com/v0/b/auth",
"id": "Z27GLizWnYTJvLQyYRQt"
},
{
"view": "https://firebasestorage.googleapis.com/v0/b/auth",
"uploadedby":"bruno",
"uploaddate":"6/27/2022",
"title":"ankitadmission",
"file":null,
"id":"rmcbUrg9TpFhQh5RLqva"
}
]
},
{
"categoryName":"syallabus",
"rows": [
{
"fullname":"bruno",
"view":"https://firebasestorage.googleapis.com/v0/b/auth",
"title":"sudhir",
"uploaddate":"8/15/2022",
"id":"hi7QEOlBzzVLZ1QHYqlk"
}
]
},
{
"categoryName":"Binodkhatricv",
"rows": [
{
"title":"binodtry",
"fullname":"bruno",
"uploaddate":"8/15/2022",
"view":"https://firebasestorage.googleapis.com/v0/b/auth",
"id":"o4EtP1xkbWMk1icp4uNH"
}
]
}
]
const result = filteritem.sort((a, b) => a.categoryName.toLowerCase().localeCompare(b.categoryName.toLowerCase()))
console.log(result)

Get directory path in Array of Objects from directory path as string

Been searching SO posts, nothing answers this for me yet.
I have an Array of folders like such :
[{
"name": "home",
"folders": [{
"name": "New Folder",
"folders": [{
"name": "53w5r",
"folders": [{
"name": "test",
"folders": []
}]
}]
}, {
"name": "public folder",
"folders": [{
"name": "cold",
"folders": []
}, {
"name": "hot",
"folders": []
}]
}, {
"name": "My Folder",
"folders": []
}]
}]
I need to find search this array using a path string such as the following :
"home,New Folder,53w5r,test"
I'm searching for that folder, so a findFolder method would take the string above and return the folder objects in the "test" folder .
Assuming that your comma-separated path will always be valid, you can use this simple method for traversing the data:
var str = "home,New Folder,53w5r,test";
var data = [{
"name": "home",
"folders": [{
"name": "New Folder",
"folders": [{
"name": "53w5r",
"folders": [{
"name": "test",
"folders": []
}]
}]
}, {
"name": "public folder",
"folders": [{
"name": "cold",
"folders": []
}, {
"name": "hot",
"folders": []
}]
}, {
"name": "My Folder",
"folders": []
}]
}];
var folderNames = str.split(",");
var result = folderNames.reduce((results, folderName, index) => {
var currFolder = results.find(folder => folder.name === folderName);
// if last folder, return entire folder, otherwise return currFolder.folders
return index === folderNames.length-1 ? currFolder : currFolder.folders;
}, data);
console.log(result);
Here is my implementation without reduce, it will return null if the directory wasn't found.
const dirSeperator = ",";
function findDir(path, dirs) {
var parts = path.split(dirSeperator);
if (parts && parts.length > 0) {
var n = parts[0];
for (var i = 0; i < dirs.length; i++) {
if (dirs[i].name === n) {
if (parts.length > 1)
return findDir(path.replace(n + dirSeperator, ''), dirs[i].folders)
else if (parts.length == 1)
return dirs[i]
}
}
return null;
} else {
return null;
}
}
var dirs = [{
"name": "Test",
"folders": [{
"name": "Test2",
"folders": [{
"name": "test 3",
"folders": []
},
{
"name": "test 3",
"folders": []
}
]
}]
},
{
"name": "Main",
"folders": [{
"name": "Test2",
"folders": [{
"name": "test 3",
"folders": []
},
{
"name": "test 3",
"folders": []
}
]
}]
}
];
const testcase = "Test,Test2,test 3";
console.log('Searching for', testcase, ' in ', dirs)
console.log(findDir(testcase, dirs))
Here's a 2 line solution:
You can use the .find method to search for a folder on a level:
(folder, name) => folder.folders.find(e => e.name == name);
Then I have written a recursive function that will look up the folders for each element of the provided path. It uses .reduce to keep track of the parent folder (acc). At the end of the loop it returns the last folder array (the one at the end of the path).
path.split(',').reduce((acc, curr) => find(acc, curr), {folders:folders});
Here's a quick demo:
const find = (folder, name) => folder.folders.find(e => e.name == name);
const getFolders = path => path.split(',').reduce((acc, curr) => find(acc, curr), {folders:folders});
console.log(
getFolders('home,New Folder,53w5r,test')
);
<script>
const folders = [{
"name": "home",
"folders": [{
"name": "New Folder",
"folders": [{
"name": "53w5r",
"folders": [{
"name": "test",
"folders": []
}]
}]
}, {
"name": "public folder",
"folders": [{
"name": "cold",
"folders": []
}, {
"name": "hot",
"folders": []
}]
}, {
"name": "My Folder",
"folders": []
}]
}]
</script>

iterate through Json array without having a key

First of all, this question might have been asked several times already, but every thread I found didn't help me. I would appreciate if one could rewrite my function below.
I have the following array with Json objects.
The goal is to get the "url" values. Right now I get every value from that array.
a = [{
"result": [{
"name": [
"name"
],
"url": [
"www.bar.com"
]
},
{
"name": [
"name 2"
],
"url": [
"www.bar.org"
]
},
{
"name": [
"name 1"
],
"url": [
"www.bar.biz"
]
},
{
"name": [
"name 3"
],
"url": [
"www.bar.jp"
]
}
]
}];
document.getElementById("foo").innerHTML = "How to explicitly get the url value?'";
loopThrough(a);
function loopThrough(obj) {
for (var key in obj) {
// skip loop if the property is from prototype
if (!obj.hasOwnProperty(key)) continue;
if (typeof obj[key] !== 'object') {
console.log(obj[key]);
} else {
loopThrough(obj[key]);
}
}
}
<div id="foo">
</div>
How would I access each "url" element in this array?
Maybe there is also a smarter solution than this.
Thank you in advance.
a = [{
"result": [{
"name": [
"name"
],
"url": [
"www.bar.com"
]
},
{
"name": [
"name 2"
],
"url": [
"www.bar.org"
]
},
{
"name": [
"name 1"
],
"url": [
"www.bar.biz"
]
},
{
"name": [
"name 3"
],
"url": [
"www.bar.jp"
]
}
]
}];
loopThrough(a);
// Uses ES6 syntax
function loopThrough(obj) {
obj[0].result.forEach(r => console.log(r.url[0]));
}
try it yourself.
var a = [{
"result": [{
"name": [
"name"
],
"url": [
"www.bar.com"
]
},
{
"name": [
"name 2"
],
"url": [
"www.bar.org"
]
},
{
"name": [
"name 1"
],
"url": [
"www.bar.biz"
]
},
{
"name": [
"name 3"
],
"url": [
"www.bar.jp"
]
}
]
}];
var urls=a[0].result.reduce(function(urls,it){
return urls.concat(it.url);
},[]);
console.log(urls);

How do I translate javascript object to a new object?

I need to import a few external json data into a variable or into a single json file to then display that data with D3.
This is the format of the data that I need to import from each json file:
{
"name": "name1",
"version": "0.1.2",
"references": [
{
"url1": "http://example1.com"
},
{
"url2": "http://example2.com"
}
]
}
And this is the format of data that I need for the final json file/variable.
{
"nodes":[
{
"name": "name1",
"version": "0.1.2",
"references": [
{
"url1": "http://example1.com"
},
{
"url2": "http://example2.com""
}
]
},
{
"name": "name2",
"version": "1.6.0",
"references": [
{
"url1": "http://example34.com"
},
{
"url2": "http://example30.com""
}
]
},
{
...
...
}
],
"links":[
]
}
Basically I need to merge the data from the different json files inside the "nodes" array.
Any idea how could I do this?
Thanks
nodes is a simple array, so you can just push the 'file' objects into the nodes array.
var file1 = {
"name": "name1",
"version": "0.1.2",
"references": [
{
"url1": "http://example1.com"
},
{
"url2": "http://example2.com"
}
]
}
var file2 = {
"name": "name1",
"version": "0.1.2",
"references": [
{
"url1": "http://example1.com"
},
{
"url2": "http://example2.com"
}
]
}
var files = [file1, file2];
var node = {
"nodes": [],
"links": []
}
files.forEach(function(file) {
node.nodes.push(file);
})
console.log(node);
If you simply need to push all the data from the imported JSON into nodes, you can do this:
var imported = {
"name": "name1",
"version": "0.1.2",
"references": [
{
"url1": "http://example1.com"
},
{
"url2": "http://example2.com"
}
]
};
var finalJson = {
nodes: []
};
finalJson.nodes.push(imported);
Here is the fiddle: https://jsfiddle.net/vj1nqeu5/1/

how to loop through the Restful web service using for loop with a object

How to loop through the Restfulwebserivice using for loop with a single object. and I don't want to use for each loop so how do i do this. i am not able to get the data by using
for(var key in data) {
alert(data[key].hotel_geo_node.name);
if(data.hasOwnProperty(key)){
data[key].hotel_geo_node.name;
}
}
here is the api code.
{
"data": {
"4325474491990470056": {
"hotel_geo_node": {
"name": "The Capitol",
"tags": {
"hotel_chain_code": [
"nichendgrp"
],
"property_type": [
"Hotel"
],
"property_budget_category": [
"Luxury"
],
"others": [
"goibibo_hotel"
]
},
},
"4325474491990470057": {
"hotel_geo_node": {
"name": "The Capitol",
"tags": {
"hotel_chain_code": [
"nichendgrp"
],
"property_type": [
"Hotel"
],
"property_budget_category": [
"Luxury"
],
"others": [
"goibibo_hotel"
]
},
},
"4325474491990470058": {
"hotel_geo_node": {
"name": "The Capitol",
"tags": {
"hotel_chain_code": [
"nichendgrp"
],
"property_type": [
"Hotel"
],
"property_budget_category": [
"Luxury"
],
"others": [
"goibibo_hotel"
]
},
}
}
}

Categories

Resources