I'm trying to create an array of objects where one of the properties of each object is a list of a few other objects from the same array. Similar to a hierarchy, each object has parent objects and children objects. I'm wondering what is the most efficient way of doing this. The first thought I had was to simply create an array of the unique IDs. So:
var network = [
{
"id": "ABCD",
"description": "some info",
"parents": [""], //no parents
"childern": ["EFG"]
},
{
"id": "EFG",
"description": "more info",
"parents": ["ABCD"],
"children": ["XYZ"]
},
{
"id": "LMNOP",
"description": "something",
"parents": ["ABCD"],
"children": ["XYZ"]
},
{
"id": "XYZ",
"description": "something",
"parents": ["EFG", "LMNOP"],
"children": [] //no child nodes
}
My concern with this approach is that everytime I want to act on a 'parent' or 'child', I only have a string of the name. I would need to search the array to match the string to whatever object has that ID. So while I can get the description of my current object with network[2].description, I can't do something like network[2].children[0].description. If the array contains hundreds or even a couple thousand objects and I'm continually searching it I'm worried about performance.
The second approach I've considered is storing the index of the parent and children nodes instead of their unique IDs. Then I could access a parent or child node with something like network[network[1].children[0]]. But in this case I'm relying on the order of objects to remain static. I plan to pull down the data from a noSQL database at the start of each user session, so I don't think I can rely on the order to remain unchanged.
Is there another approach? As I think about C++ I would probably be able to store a pointer, but I don't think I can do that in JS.
I suggest you store your objects in an object, not an array. You can then use the id as the key (aka pointer) to look up the object:
var network = {
"ABCD": {
"id": "ABCD",
"description": "some info",
"parents": [""], //no parents
"children": ["EFG"]
},
"EFG": {
"id": "EFG",
"description": "more info",
"parents": ["ABCD"],
"children": ["XYZ"]
},
"LMNOP": {
"id": "LMNOP",
"description": "something",
"parents": ["ABCD"],
"children": ["XYZ"]
},
"XYZ": {
"id": "XYZ",
"description": "something",
"parents": ["EFG", "LMNOP"],
"children": [] //no child nodes
}
}
// access a parent like this
let parent0 = network["XYZ"]["parents"][0];
console.log(parent0);
// get an array of your node IDs like this
let nodeIds = Object.keys(network);
console.log(nodeIds);
// can still look up by position then
console.log(network[nodeIds[0]]);
Of course you can do it using references to your objects
var a = {
"id": "ABCD",
"description": "some info",
"parents": [], //no parents
"children": []
};
var b = {
"id": "EFG",
"description": "more info",
"parents": [],
"children": []
};
var c = {
"id": "LMNOP",
"description": "something",
"parents": [],
"children": []
};
var d = {
"id": "XYZ",
"description": "something",
"parents": [],
"children": [] //no child nodes
};
a.children.push(b);
b.parents.push(a);
//and so on.
var network = [a,b,c,d];
Related
Let's say we have some houses represented as JSON. Something like this:
[
{
"id": "1",
"code": "1",
"name": "Smith's",
"children": [
{
"id": "",
"code": "11",
"name": "Kitchen",
"children": [
{
"id": "",
"code": "111",
"name": "Sink",
"children": []
}
]
},
{
"id": "",
"code": "12",
"name": "Living Room",
"children": [
{
"id": "",
"code": "121",
"name": "Television",
"children": [
{
"id": "",
"code": "1211",
"name": "Panel buttons",
"children": [
{
"id": "",
"code": "12111",
"name": "Power button",
"children": []
},
{
"id": "",
"code": "12112",
"name": "Colors adjust button",
"children": []
}
]
},
{
"id": "",
"code": "1221",
"name": "Screen",
"children": []
}
]
}
]
}
]
},
{
"id": "2",
"code": "2",
"name": "Taylor's",
"children": [
// Here goes all house places and items like the example above
]
},
{
"id": "1",
"code": "1",
"name": "Wilson's",
"children": [
// Here goes all house places and items like the example above
]
}
]
Take notice that the "code" property, found in each item, is something to represent the "path" until that item, carrying its parents "code" property concatenated with its own position by incremental order. So the code "11" means house 1 and child 1. And 212 would be house 2, child 1, child 2. Also take notice that all items follow the same type. In other words, every item has a children that follows its own type. So, it could be infinite.
Now, I'd like to maintain these structure. Adding items, updating items and so on. Let's say we want to add a carpet in Smith's living room. We would go deep in the structure 2 levels, which are Smith's house (index 0 of the array) and living room (index 1 of the children array). And then add a carpet.
The problem is it won't be 2 levels in all cases. What if I wanted to add a bathroom? It would be level 1, alongside with kitchen in living room (the first children). What if I'd like to add a microwave in the kitchen and add to it buttons, display, etc?
I think I'm a recursive scenario where I have to visit all items and, if it is the one I'm looking to reach at, add/updated it.
I've tried following this example
I couldn't figure it out how to bring it to my case. though.
I appreciate if your contribution is in JavaScript, but feel free to represent it in other language in case you are better in other language =).
There are indeed some questions, like for instance what happens if you have more than 10 items as child and why do you need it?
And what happens if you remove any item on any level? will you recursively start updating all codes?
Nevertheless I gave it a go. In essence what I do in the code is first search for the parent (example: Kitchen) where you want to add it to and then add the new child item (example: Carpet) to it.
The search is a typical recursive search.
The child addition is a typical addition to an array.
For argument's sake I assumed that the fields code always exist and that children is always an array.
// Actual code is underneath the declaration of this array
let houseList = [
{
"id": "1",
"code": "1",
"name": "Smith's",
"children": [
{
"id": "",
"code": "11",
"name": "Kitchen",
"children": [
{
"id": "",
"code": "111",
"name": "Sink",
"children": []
}
]
},
{
"id": "",
"code": "12",
"name": "Living Room",
"children": [
{
"id": "",
"code": "121",
"name": "Television",
"children": [
{
"id": "",
"code": "1211",
"name": "Panel buttons",
"children": [
{
"id": "",
"code": "12111",
"name": "Power button",
"children": []
},
{
"id": "",
"code": "12112",
"name": "Colors adjust button",
"children": []
}
]
},
{
"id": "",
"code": "1221",
"name": "Screen",
"children": []
}
]
}
]
}
]
},
{
"id": "2",
"code": "2",
"name": "Taylor's",
"children": [
// Here goes all house places and items like the example above
]
},
{
"id": "1",
"code": "1",
"name": "Wilson's",
"children": [
// Here goes all house places and items like the example above
]
}
]
addChild(houseList,"11",{name:"Carpet" });
addChild(houseList,"1211",{name: "Volume Up Button"});
addChild(houseList,"1211",{name: "Volume Down Button"});
console.log('new houselist', houseList);
// child is just what you want to add and the parentCode refers to where you want to add it to
function addChild(houseList, parentCode, child) {
let parent = findInHouseList(houseList,parentCode,child);
let amountOfChildren = parent.children.length;
let newCodeName = parentCode +""+ (amountOfChildren+1);
child = {...{id: "", code: newCodeName, children: []}, ...child};
console.log('adding child ', child);
parent.children = [...parent.children, child];
}
function findInHouseList(houseList,code) {
for (let house of houseList) {
let foundElement = findElement(house,code);
if ( foundElement)
return foundElement;
}
}
function findElement(currentElement, code) {
if ( currentElement.code === code)
return currentElement;
if (currentElement.children?.length > 0)
{
for (let child of currentElement.children) {
let foundElement = findElement(child,code);
if ( foundElement)
return foundElement;
}
}
return null;
}
I decided to let the code manage the code names for new children. It seems the easiest.
What you're trying to do is updating a JSON value at a dynamic path.
This function will append a child to the item which holds the specified code.
You may add conditions to check if the item at the code is defined
function appendChild(houses, code, item) {
let path = code.split('')
let o = houses
for (let i = 0; i < path.length; i++) {
let n = path[i] - 1
o = o[n]["children"]
}
o.push(item)
return houses
}
However, you should start your code indexes at 0 and storing them inside the JSON is useless since they are simply the path to reach the item.
This question already has answers here:
Object array clone with subset of properties
(3 answers)
Closed 4 years ago.
I have an array of objects:
const ObjArray= [{
"id": "90e17e10-8f19-4580-98a8-ad05f4ecd988",
"name": "john",
"description": "worker",
"place": "f.1.1",
...
},
{
"id": "90e17e10-8eqw-4sdagfr4ecd9fsdfs",
"name": "joe",
"description": "dev",
"stepType": "d.2.1",
...
}
];
I want to filter the array of objects above to return only specific properties from the objects.
Let's say I want to return only the id and the name of every object in a new array that would look like this:
[{
"id": "90e17e10-8f19-4580-98a8-ad05f4ecd988",
"name": "john"},
{
"id": "90e17e10-8eqw-4sdagfr4ecd9fsdfs",
"name": "joe" }
I searched about that but I couldn't find out how to get it the way I want.
IMHO, you are looking for something like this using Array#map:
ObjArray= [{
"id": "90e17e10-8f19-4580-98a8-ad05f4ecd988",
"name": "john",
"description": "worker",
"place": "f.1.1" },
{
"id": "90e17e10-8eqw-4sdagfr4ecd9fsdfs",
"name": "joe",
"description": "dev",
"stepType": "d.2.1",}
];
console.log(ObjArray.map(o => ({'id': o['id'], 'name': o['name']})));
If you prefer object destructuring:
ObjArray= [{
"id": "90e17e10-8f19-4580-98a8-ad05f4ecd988",
"name": "john",
"description": "worker",
"place": "f.1.1" },
{
"id": "90e17e10-8eqw-4sdagfr4ecd9fsdfs",
"name": "joe",
"description": "dev",
"stepType": "d.2.1",}
];
console.log(ObjArray.map(({id, name}) => ({id, name})));
I've got a json array like this
this.nodes = [
{
"id": 1,
"parent": null,
"name": "",
"children": [
{
"id": 2,
"parent": 1,
"name": "ok it works",
"children": []
},
{
"id": 4,
"parent": 1,
"name": "ok it works",
"children": []
}
]
},
{
"id": 3,
"parent": null,
"name": "",
"children": [
{
"id": 5,
"parent": 3,
"name": "ok it works",
"children": []
},
{
"id": 6,
"parent": 3,
"name": "",
"children": []
}
]
}
]
what is the fastest way to empty the array, I've tried
this.nodes = []
but got this error after running that line
vendor.f0f5c3b4d9bf656cfa2b.js:8 ERROR SyntaxError: Unexpected end of JSON input
at JSON.parse (<anonymous>)
at Response.Body.json (vendor.f0f5c3b4d9bf656cfa2b.js:641)
at MapSubscriber.project (app.f0f5c3b4d9bf656cfa2b.js:171)
at MapSubscriber._next (vendor.f0f5c3b4d9bf656cfa2b.js:676)
at MapSubscriber.Subscriber.next (vendor.f0f5c3b4d9bf656cfa2b.js:420)
at XMLHttpRequest.a (vendor.f0f5c3b4d9bf656cfa2b.js:655)
at ZoneDelegate.invokeTask (polyfills.f0f5c3b4d9bf656cfa2b.js:36)
at Object.onInvokeTask (vendor.f0f5c3b4d9bf656cfa2b.js:36)
at ZoneDelegate.invokeTask (polyfills.f0f5c3b4d9bf656cfa2b.js:36)
at Zone.runTask (polyfills.f0f5c3b4d9bf656cfa2b.js:36)
I've got a deeply nested array of json objects, so is there a quick way to delete it all, reset it to an empty array without having to recursivly go through the whole tree and delete each child first before deleting the parent all the way up to the main parent?
Btw I am running this inside Angularjs and I render a set of nested components based on the array I showed you above.
Store this into a variable, hence:
var vm = this;
vm.nodes = [.....];
vm.nodes = [];
On my ASP.NET backend, I return an array of models, called Job, that can have n amount of jobs as children, using SignalR. One job could look like this:
{
"id": 0,
"json": '{"error": "Some error"}',
"children": [{
"id": 1
}, {
"id": 3,
"children": [{
"id": 4,
"json": '{"error": "Some other error"}'
}]
}]
}
As you can see, each job can have a child, which can have another child, and so on. Each job also has a json property, which is JSON in a text string. I want to deserialize these to a regular JavaScript object, which looks like this:
var deserialized = {
"id": 0,
"json": {
"error": "Some error"
},
"children": [{
"id": 1
}, {
"id": 3,
"children": [{
"id": 4,
"json": {
"error": "Some other error"
}
}]
}]
}
So basically goes like this:
If the job has a json property simply do job.json = JSON.parse(job.json)
If the job has children, loop over all the children
Repeat 1
How can I achieve this? I guess recursion is a way, but I'd rather see if it's possible to utilize the new ES6 methods.
1.If the job has a json property simply do job.json = JSON.parse(job.json)
2.If the job has children, loop over all the children
3.Repeat 1
Suppose, in a job you have both properties json with JSON string and also children then we have to execute both the points (1 & 2) one by one to convert the nested json property of the job into JSON Object.
In that case, first we have to convert the json property into JSON Object and then again we have to iterate the whole job with children array.
Try Array filter() method with ES6 Arrow function.
Working Demo :
let jobs = [{
"id": 0,
"json": '{"error": "Some error"}',
"children": [{
"id": 1
}, {
"id": 3,
"children": [{
"id": 4,
"json": '{"error": "Some other error"}'
}]
}]
},
{
"id": 1,
"json": '{"error": "Some error"}',
"children": [{
"id": 2
}, {
"id": 4,
"children": [{
"id": 5,
"json": '{"error": "Some other error"}'
}]
}]
}];
function parseObj(job) {
let res;
if (typeof job !== 'object') {
return;
} else {
res = job.filter(elem => (elem.json && typeof elem.json == 'string')?elem.json = JSON.parse(elem.json):parseObj(elem.children))
.filter(elem => (elem.json && typeof elem.json == 'string')?elem.json = JSON.parse(elem.json):parseObj(elem.children));
}
return res;
}
console.log(parseObj(jobs));
This question already has an answer here:
Filter collection (array of objects) based on other array
(1 answer)
Closed 6 years ago.
I have an object and an array
{
"library_items":
[
{
"id": "23493",
"artifactID": "",
"title":"Physics Lecture",
"authors": [{
"name": "Don Johnson",
"artifactID": "",
"role": "author",
"roleID": ""
}],
"artifactType": "games",
"domain": {
"branch": "",
"description": "",
"branchInfo": {
"branch": "",
"subject": "Physics"
}
},
"type": {
"description": "",
"id": "",
"name": ""
}
},
{
"id": "23493",
"artifactID": "",
"title":"Chemistry Lecture",
"authors": [{
"name": "Don Johnson",
"artifactID": "",
"role": "author",
"roleID": ""
}],
"artifactType": "games",
"domain": {
"branch": "",
"description": "",
"branchInfo": {
"branch": "",
"subject": "Chemistry"
}
},
"type": {
"description": "",
"id": "",
"name": ""
}
}
]
}
I have another array
var subjects = ['Physics', 'Biology', 'Mathematics']
how do I filter the Object using the array values in "subjects"?. I mean I want to get items from the object which have subject corresponding to any of the array values.
Basically, making use of filter and indexOf methods.
filter Make use of this method to filter the array as per the matching criteria as defined in the callback function.
indexOf To check if the Array contains a value.
Note: There is another method includes which can check for existence of an element in an array, which is part of ES7 draft but it is not supported by many browsers.
var items = {
"library_items":
[
{
"id": "23453",
"artifactID": "",
"title":"Physics Basics",
"subject": "Physics"
},
{
"id": "23453",
"artifactID": "",
"title":"Chemistry Basics",
"subject": "Chemistry"
}
]
};
var subjects = ['Physics', 'Biology', 'Mathematics'];
var filtered = items.library_items.filter((x) => subjects.indexOf(x.subject) > -1);
console.log(filtered);
You could use Array#filter and Array#includes
var items = { library_items: [{ id: "23453", artifactID: "", title: "Physics Basics", subject: "Physics" }, { id: "23453", artifactID: "", title:"Chemistry Basics", subject: "Chemistry" }] },
subjects = ['Physics', 'Biology', 'Mathematics'],
filtered = items.library_items.filter(x => subjects.includes(x.subject));
console.log(filtered);
I use lodash (https://lodash.com/docs) in every project. They have build a massive array of methods and wrappers that will make your live much easier.
var items = {
"library_items":
[
{
"id": "23453",
"artifactID": "",
"title":"Physics Basics",
"subject": "Physics"
},
{
"id": "23453",
"artifactID": "",
"title":"Chemistry Basics",
"subject": "Biology"
}
]
};
var subjects = ['Physics', 'Physics', 'Mathematics'];
_.find(items["library_items"], function(o) {
return subjects.indexOf(o.subject) > -1;
});
If you do not want to install additional packages I'd go with Agalo's answer!
If performance is important to you. I would suggest another approach to you.
With filter and indexOf(or includes) your performance of the algorithm is O(n*m). For each library item you need to go through each subject.
If you create a simple hash table from subjects array first you can archive O(n+m). First, you go through each subject and write it to the hash table then for each library item you can check with O(1)(because of the hash table) whether you need that item.
Here is the code example:
var items = {
"library_items":
[
{
"id": "23453",
"artifactID": "",
"title":"Physics Basics",
"subject": "Physics"
},
{
"id": "23453",
"artifactID": "",
"title":"Chemistry Basics",
"subject": "Chemistry"
}
]
};
var subjects = ['Physics', 'Biology', 'Mathematics'];
var allSubjects = {};
subjects.forEach(s => allSubjects[s] = true);
var filtered = items.library_items.filter(x => allSubjects[x.subject]);
console.log(filtered);
result = obj.library_items.filter(o => subjects.indexOf(o.subject) > -1)