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;}
I have a data array, there are multiple objects in this array, and the data object is an array. There may be more than one object in this array. How can I copy these objects under a single array?
const test = []
const data = [
{
"_id": "124141",
"name": "test",
"data": [
{
"price":10,
"title": "sda"
},
]
},
{
"_id": "2525",
"name": "test2",
"data": [
{
"price":20,
"title": "asdas"
},
]
}
]
[{
"price":10,
"title": "sda"
},
{
"price":20,
"title": "asdas"
},
]
If this is the output I expect, it should be like this. how can I do that
const data = [
{
"_id": "124141",
"name": "test",
"data": [
{
"price":10,
"title": "sda"
},
{
"price":99,
"title":"aaaaa"
}
]
},
{
"_id": "2525",
"name": "test2",
"data": [
{
"price":20,
"title": "asdas"
},
]
}
];
console.log(data.map(e => e.data).flat());
// OR
console.log(data.flatMap(e => e.data));
I have an object that looks like this :
{
"mark": [
{
"id":1,
"name": "mark",
"age":26
},
{
"id":2,
"name": "mark",
"age":25
}
],
"jack": [
{
"id":1,
"name": "jack",
"age":26
},
{
"id":2,
"name": "jack",
"age": 24,
}
]
}
WHAT I GOT AS OUTPUT IF A NEW USER IS ADDED IT IS NOT APPENDED, BUT IT IS OVERWRITTEN OR CREATED AS A NEW OBJECT
{
"mark": [
{
"id":1,
"name": "mark",
"age":26
},
{
"id":2,
"name": "mark",
"age":25
}
],
"jack": [
{
"id":1,
"name": "jack",
"age":26
},
{
"id":2,
"name": "jack",
"age": 24,
}
],
} "Josh": [
{
"id":1,
"name": "Josh",
"age":26
},
{
"id":2,
"name": "Josh",
"age": 24,
}
]
Expected
if new person data arrives in my JSON File, that should be appended to the next array with key values of array of Objects,
like
{
"mark": [
{
"id":1,
"name": "mark",
"age":26
},
{
"id":2,
"name": "mark",
"age":25
}
],
"jack": [
{
"id":1,
"name": "jack",
"age":26
},
{
"id":2,
"name": "jack",
"age": 24,
}
],
"Josh": [
{
"id":1,
"name": "Josh",
"age":26
},
{
"id":2,
"name": "Josh",
"age": 24,
}
]
}
I've tried this method after reading the JSON file
var newObject = array.reduce(function (obj, value) {
var key = `${value.name}`;
if (obj[key] == null) obj[key] = [];
obj[key].push(value);
return obj;
}, {});
console.log(newObject);
fs.appendFile("users.json", newObject, (err) => {
res.send(JSON.stringify(newObject));
});
Like the advice already given, but using async fs i/o.
import { promises as fs } from 'fs'; // or require('fs').promises
// inside the OP's route
const filename = 'users.json';
try {
const array = await fs.readFile(filename);
// OP's code here
// const newObject = array.reduce(...
await fs.writeFile(filename, newObject);
return res.send(JSON.stringify(newObject));
} catch (error) {
return res.status(500).send({ message: 'error' });
}
Also note that all this is what a database does.
You have to first read the data from the JSON and append the new object to the JSON data and then write it back to the file.
const data = fs.readFileSync('users.json');
.
.
fs.writeFileSync('users.json', {...data, ...newObject});
How can I add custom colors to only output channel created by my extension?
Currently I have this package.json
{
"name": "mytestextension-output-colors",
"displayName": "My test extension - output colors",
"version": "0.0.1",
"publisher": "nobody",
"engines": {
"vscode": "^1.72.0"
},
"main": "./extension.js",
"activationEvents": [
"onStartupFinished"
],
"contributes": {
"languages": [
{
"id": "mytestextension-output",
"aliases": [],
"mimetypes": [
"text/x-code-output"
]
}
],
"grammars": [
{
"language": "mytestextension-output",
"scopeName": "text.mytestextension-output",
"path": "./mytestextension-output.tmLanguage.json"
}
],
"configuration": {
"type": "object",
"title": "My Test Extension - output colors"
},
"configurationDefaults": {
"editor.tokenColorCustomizations": {
"textMateRules": [
{
"scope": "mytestextension-output-red",
"settings": {
"foreground": "#f00080"
}
}
]
}
}
}
}
extension.js
const window = require("vscode").window;
function activate() {
const out = window.createOutputChannel("myextension test output", "mytestextension-output");
out.appendLine(`red output`);
}
function deactivate() {}
module.exports = {
activate,
deactivate
};
mytestextension-output.tmLanguage.json
{
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
"name": "mytestextension-output",
"scopeName": "text.mytestextension-output",
"patterns": [ {
"match": ".*",
"name": "mytestextension-output-red"
}
]
}
Even though the grammar is set for mytestextension-output id/scope, it applied to and changes color to red in all output channels (git, tasks, extensions, etc)
What am I missing here?
Gist example
Attempting to restructure nested JSON data (data1) into "proper" format (data2)
with no success so far.
data1 is generated based on a given parent directory (recipes) that looks for html files.
data2 is what I'm trying to output using data1 since whatever content inside a folder is better represented as array of objects than just pure nested objects.
var data1 = {
"cake": {
"chocolate": {
"black-forest": {
"name": "Black Forest",
"path": "recipes/cake/chocolate/black-forest.html"
},
"new-shortcake": {
"milk-chocolate-shortcake": {
"name": "Milk chocolate shortcake",
"path": "recipes/cake/chocolate/shortcake/milk-chocolate-shortcake.html"
},
"dark-chocolate-shortcake": {
"name": "Dark chocolate shortcake",
"path": "recipes/cake/chocolate/shortcake/dark-chocolate-shortcake.html"
}
}
}
},
"pasta": {
"spaghetti": {
"aglio-olio": {
"name": "Spagehetti Aglio Olio",
"path": "recipes/pasta/spaghetti/aglio-olio.html"
},
"carbonara": {
"name": "Carbonara",
"path": "recipes/pasta/spaghetti/carbonara.html"
}
},
"lasagna": {
"name": "Lasagna",
"path": "recipes/pasta/lasagna.html"
}
}
}
var data2 = [
{
"name": "cake",
"children": [
{
"name": "chocolate",
"children": [
{
"name": "Black Forest",
"path": "recipes/cake/chocolate/black-forest.html"
},
{
"name": "New Shortcake",
"children": [
{
"name": "Milk chocolate shortcake",
"path": "recipes/cake/chocolate/shortcake/milk-chocolate-shortcake. html"
},
{
"name": "Dark chocolate shortcake",
"path": "recipes/cake/chocolate/shortcake/dark-chocolate-shortcake. html"
}
]
}
]
}
]
},
{
"name": "pasta",
"children": [
{
"name": "spaghetti",
"children": [
{
"name": "Spagehetti Aglio Olio",
"path": "recipes/pasta/spaghetti/aglio-olio.html"
},
{
"name": "Carbonara",
"path": "recipes/pasta/spaghetti/carbonara.html"
}
]
},
{
"name": "Lasagna",
"path": "recipes/pasta/lasagna.html"
}
]
}
]
https://codepen.io/kyooriouskoala/pen/LLLXmG
Any help much appreciated!
PS: End goal is to build a menu with the new data structure.
I hope this output is what you meant.
var final = [];
function tree(object, temp){
for(var key in object){
var folder = {};
if(object[key] !== null && typeof object[key] == 'object'){
//console.log(key);
if(_.has(object[key], "path")){
folder.name = object[key].name;
folder.path = object[key].path;
folder.children = [];
} else{
folder.name = key;
folder.children = object[key];
}
final.push(folder);
tree(object[key]);
}
}
return final;
}
This outputs your data as a associative object with values needed.