Unix-like path converted to json with javascript - javascript

I'm migrating from python to javascript. So now, I'm working on a react project where I need to convert some unix-like path to json. Actually, there aren't folders, they're list of categories joined by "/".
Here is what I have:
Category Model holds the categories and the slug play as categories list joined by "/"
const categorySchema = mongoose.Schema({
name: { type: String, required: true },
slug: { type: String, unique: true }, // Repr the route
image: { type: String },
topLevel: { type: String },
description: { type: String },
}, { timestamps: true });
One representation of a category is like this:
{
name: "embedded",
slug: "/electronics/embedded",
image: "/some/image.png",
topLevel: "electronics",
description: "This is a brief description."
}
Now what I want is when I have a list of object like this
[
{
id: 1,
name: "embedded",
slug: "/electronics/embedded",
image: "/some/image.png",
topLevel: "electronics",
description: "This is a brief description."
},
{
id: 2,
name:"electonics",
slug:"/electronics",
topLevel: "electronics",
image: "/some/image.png",
description: "..."
},
{
id: 3,
name: "house",
slug: "/house",
topLevel: "house",
image: "/some/image.png",
description: "...",
}
]
to end up having from the slug which are the unix-like paths as:
[
{
id: 2,
node: "electronics",
children: [{
id: 1,
node: "embedded",
children: [],
}],
},
{
id: 3,
node: "house",
children: []
},
]
This is what I'm really struggling trying to have. If someone can help, you are more than welcome.

Based on yesterday's comment on whether I've tried something yet or not, I have basically come up with something but still not perfect because I didn't walk deep the whole tree.
Based on the input data and the type of output I want to have, this is my first trial:
function listToTree(list) {
var node,
i,
roots = [];
for (i = 0; i < list.length; i += 1) {
node = list[i];
var slugList = node.slug.split("/").filter((x) => x !== "");
var children = [];
if (slugList.length > 1) {
var parent = slugList.shift();
var parentNode = {
node: parent,
id: node.id,
children: [],
};
roots.push(parentNode);
for (var j = 0; j < slugList.length; j++) {
var child = {
id: node.id,
node: slugList[j],
children: [],
};
children.push(child);
}
roots[i].children = [...children];
} else {
roots.push({
node: node.topLevel,
id: node.id,
children: [],
});
}
}
return roots;
}
The output:
const roots = listToTree(exampleData);
console.log(roots[0]);
{
node: 'electronics',
id: 1,
children: [ { id: 1, node: 'embedded', children: [] } ]
}
So, I still need some help and to be honest this answer here, not yet perfect, was inspired by the answered made by Halcyon in here

Related

Recursive search for the object's parent array using for loop

data=[
{
id: 1,
name: "Model",
type: "directory",
path: "/path/to/folder",
children: [
{
id: 2,
name: "model.yaml",
type: "file",
path: "../../storage/model.yaml",
},
],
},
{
id: 3,
name: "Inventory",
type: "directory",
path: "/path/to/folder",
children: [
{
id: 4,
name: "inventory.yaml",
type: "file",
path: "../../storage/inventory.yaml",
},
],
},
{
id: 5,
name: "UI",
type: "directory",
path: "/path/to/folder",
children: [
{
id: 6,
name: "elements",
type: "directory",
path: "../../storage",
},
{
id: 7,
name: "viewmodel",
type: "directory",
path: "../../storage",
},
{
id: 8,
name: "i18n",
type: "directory",
path: "../../storage",
},
{
id: 9,
name: "index.template.html",
type: "file",
path: "../../storage/index.template.html",
},
],
},
{
id: 10,
name: "DeviceConnector",
type: "directory",
children: [],
},
];
function getParent(data, id) {
for (let i = 0; i < data.length; i++) {
if (data[i].id === id) {
return data;
} else if (data[i].children && data[i].children.length) {
return data[i].children;
} else if (data[i].children && data[i].children.length) {
getParent(data[i].children, id);
}
}
}
I would to make a recursive search for the object's parent array using for loop. My problem is that the loop is stopping when finding the first children occurence. Looking for a way to fix the function and make the work of it possible on any nested level.
What I'm trying to do is by calling, for example getParent(data,4), to get a parent array with one element of id = 4.
You could store the result of a recursive call and if the value is truthy, you could exit the loop with the found array.
function getParent(data, wanted) {
for (const { id, children } of data) {
if (id === wanted) return data;
const temp = children && getParent(children, wanted);
if (temp) return temp;
}
}

For loop on javascript object

I have this javascript object:
var input = [
{
id: 1,
title: 'michael',
favorite: 'bmw'
},
{
id: 2,
title: 'steve',
favorite: 'bentley'
},
{
id: 3,
title: 'denise',
favorite: 'ford'
},
]
And this is my function, it is supposed to loop through input and when called with console.log print a specific favorite, depending on which element on the list has been read by the loop.
findYourFavorite = function() {
for(let x=0; x<3; x++) {
if(input[x].title) {
var response = input[x].favorite
}
}
return response
}
If I run console.log(findYourFavorite('michael')) it will always print the same title, which is the last one in the javascript object (denise).
Ex:
console.log(findYourFavorite('michael'))
ford
It is not working randomly, as it should, I hope I'm explaining myself, if You need further clarification please do let me know.
Your condition if(input[x].title) { makes no sense - all the titles are truthy. Only assign to response if the title is equal to the parameter (which you also need to define).
var input = [
{
id: 1,
title: 'michael',
favorite: 'bmw'
},
{
id: 2,
title: 'steve',
favorite: 'bentley'
},
{
id: 3,
title: 'denise',
favorite: 'ford'
},
];
const findYourFavorite = function(titleToFind) {
for(let x=0; x<3; x++) {
if(input[x].title === titleToFind) {
var response = input[x].favorite
return response;
}
}
}
console.log(findYourFavorite('denise'))
Or, much more concisely, use .find:
var input = [
{
id: 1,
title: 'michael',
favorite: 'bmw'
},
{
id: 2,
title: 'steve',
favorite: 'bentley'
},
{
id: 3,
title: 'denise',
favorite: 'ford'
},
];
const findYourFavorite = (titleToFind) => input
.find(({ title }) => title === titleToFind)
.favorite;
console.log(findYourFavorite('denise'))

Filtering an array of objects Vue

I have an array of objects and Im trying to filter by matching ids
//Vehicle is added to quote
function filterByID(item) {
return item.id === 1;
}
this.vehicle = this.data.filter(filterByID);
data is as follows:
data: [
0: {
id: 0,
name: name
},
1: {
id: 1,
name: name
},
2: {
id: 2,
name: name
}
]
Im getting an empty error when I check the vehicle part
Are you using it like this:
const data = [
{
id: 0,
name: '',
},
{
id: 1,
name: '',
},
{
id: 2,
name: '',
},
];
function filterByID(item) {
return item.id === 1;
}
console.log(data.filter(filterByID)); // output: [{ "id": 1, "name": "" }]
You don't always need to define a separate function, you can use an arrow function, as below.
const data = [{
id: 0,
name: name
},
{
id: 1,
name: name
},
{
id: 2,
name: name
}
]
const vehicle = data.filter(item => item.id === 1);
console.log(vehicle);
This works fine in pure JS, it looks like it might be an issue with the lifecycle or state of your application. Use console.log to make sure that this.data is what you expect it to be

filter is not working for third child level (nested level)

I'm trying to filter an array having nested level of 3.. I have to filter this array at the last level.
array = [{
children: [{
children: [{
children: [],
id: 2694,
name: "Some Random data"
}, {
children: [],
id: 2695,
name: "Another Random Data"
}],
id: 2574,
name: "Test data",
}],
id: 2530,
name: "Main Test data"
}, {
children: [{
children: [{
children: [],
id: 2696,
name: "Secondary test Data"
}, {
children: [],
id: -1,
name: "Random Text"
}],
id: 2575,
name: "Another random Text"
}],
id: 2531,
name: "New Data"
}]
I have tried this function
function(random){
let array3=[];
this.array.forEach(cap=>{
let tempparent={...cap};
let child1= tempparent.children.forEach(ch=>{
let tempfeat={...ch};
let tempchildren = tempfeat.children.filter(fe=>{
if(fe.id!=random.id){
return fe
}
});
// console.log(tempchildren)
tempfeat.children = tempchildren;
// console.log(tempfeat.children)
});
console.log(child1)
tempparent.children= child1;
console.log(tempparent.children)
nodes3.push(tempparent)
})
this.array= array3
console.log(this.array);
}
I want to filter it at third level using id value. when the id matches the matched object must be removed.
You could take a dynamic approach and take the children out of the object, check the id and if found, ignore the object.
Otherwise take the children and get a subset with a recursive call and rebuild a new object and push this one to the result set.
This approach does not mutate the original data, but returns all new objects and works for an arbitrary count of levels.
function remove(array, id) {
return array.reduce((r, { children, ...o }) => {
if (o.id === id) return r;
children = remove(children || [], id);
if (children.length) o.children = children;
r.push(o);
return r;
}, []);
}
var data = [{ children: [{ children: [{ children: [], id: 2694, name: "Some Random data" }, { children: [], id: 2695, name: "Another Random Data" }], id: 2574, name: "Test data", }], id: 2530, name: "Main Test data" }, { children: [{ children: [{ children: [], id: 2696, name: "Secondary test Data" }, { children: [], id: -1, name: "Random Text" }], id: 2575, name: "Another random Text" }], id: 2531, name: "New Data" }],
result = remove(data, 2574);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use recursive function.
For example, like this
function removeById(_id,arr){
if(arr.id === _id){
return true;
}else{
arr.children.forEach(currentItem => {
if(getById(_id,currentItem)){
arr.children = arr.children.filter(x=>x.id !== _id);
}
});
}
}
and using this function
removeById(2694,array[0]);
removeById(2694,array[1]);
please examine example

Finding a path to target object in nested array of objects in Javascript

I'm currently working through a problem that I'm having some trouble figuring out where I need to find a child node in an array of objects. The target could be one or many levels deep.
The issue is, once I find the object, I also need to push the path I took to get to that object into the resulting data array.
Currently, I have written code that can successfully find the child node:
const buildFullTree = (tree, cat, data = []) => {
let collection = [tree]
while (collection.length) {
let node = collection.shift()
if (node.id === cat.id) {
data.push(node)
}
collection.unshift(...node.children)
}
return data
}
However, this isn't sufficient in terms of getting the path taken to that object.
I'm pretty sure that I need to change this to a recursive depth-first search solution in order to achieve what I'm looking for, but I am not sure how to change the while loop to accomplish this.
If I understand your question correctly, then perhaps you could revise your path search function like so to achieve what you require:
const buildFullTree = (departmentTree, category, data = []) => {
const findPath = (node, category) => {
//If current node matches search node, return tail of path result
if (node.id === category.id) {
return [node]
} else {
//If current node not search node match, examine children. For first
//child that returns an array (path), prepend current node to that
//path result
for (const child of node.children) {
const childPath = findPath(child, category)
if (Array.isArray(childPath)) {
childPath.unshift(child)
return childPath
}
}
}
}
const foundPath = findPath(departmentTree, category)
// If search from root returns a path, prepend root node to path in
// data result
if (Array.isArray(foundPath)) {
data.push(departmentTree)
data.push(...foundPath)
}
return data
}
const departmentTree = {
id: 5,
title: 'department',
level: 1,
children: [{
id: 1,
parentId: 5,
title: 'category',
level: 2,
children: [{
id: 15,
parentId: 1,
title: 'subcategory',
level: 3,
children: []
}, {
id: 18,
parentId: 1,
level: 3,
title: 'subcategory',
children: []
}, {
id: 26,
parentId: 1,
level: 3,
title: 'subcategory',
children: [{
id: 75,
parentId: 26,
level: 4,
title: 'sub-subcategory',
children: []
}, {
id: 78,
parentId: 26,
level: 4,
title: 'sub-subcategory',
children: []
}]
}]
}, {
id: 23823,
title: 'category',
level: 2,
children: []
}, {
id: 9,
parentId: 5,
level: 2,
title: 'category',
children: [{
id: 48414,
parentId: 9,
level: 3,
title: 'subcategory',
children: []
}, {
id: 2414,
parentId: 9,
level: 3,
title: 'subcategory',
children: []
}, {
id: 42414,
parentId: 9,
level: 3,
title: 'subcategory',
children: [{
id: 2323213,
parentId: 42414,
level: 4,
title: 'sub-subcategory',
children: []
}, {
id: 322332,
parentId: 42414,
level: 4,
title: 'sub-subcategory',
children: []
}]
}]
}]
};
console.log('Path to 2323213:',
buildFullTree(departmentTree, {
id: 2323213
}).map(node => node.id).join(' -> '))
console.log('Path to 23823:',
buildFullTree(departmentTree, {
id: 23823
}).map(node => node.id).join(' -> '))
console.log('Path to -1 (non existing node):',
buildFullTree(departmentTree, {
id: -1
}).map(node => node.id).join(' -> '))

Categories