I'm trying to restructure the JSON array in following manner. In the output, I need id as key and object itself as it's value.
Sample input:
[
{
"id": "1",
"children": [
{
"id": "1-1",
"children": [
{
"id": "1-1-1",
"children": []
},
{
"id": "1-1-2",
"children": []
}
]
},
{
"id": "1-2",
"children": []
}
]
},
{
"id": "2",
"children": []
},
{
"id": "3",
"children": [
{
"id": "3-1",
"children": []
}
]
}
]
Required output:
{
"1": {
"id": "1",
"children": {
"1-1": {
"id": "1-1",
"children": {
"1-1-1": {
"id": "1-1-1",
"children": []
},
"1-1-2": {
"id": "1-1-2",
"children": []
}
}
},
"1-2": {
"id": "1-2",
"children": []
}
}
},
"2": {
"id": "2",
"children": []
},
"3": {
"id": "3",
"children": {
"3-1": {
"id": "3-1",
"children": []
}
}
}
}
The following code gives me almost the required answer.
function restruct(arr) {
var newArray = arr.map(function(obj) {
var t = {};
if (obj.children)
obj.children = restruct(obj.children);
t[obj.id] = obj;
return t;
});
return newArray;
}
The output is:
[
{
"1": {
"id": "1",
"children": [
{
"1-1": {
"id": "1-1",
"children": [
{
"1-1-1": {
"id": "1-1-1",
"children": []
}
},
{
"1-1-2": {
"id": "1-1-2",
"children": []
}
}
]
}
},
{
"1-2": {
"id": "1-2",
"children": []
}
}
]
}
},
{
"2": {
"id": "2",
"children": []
}
},
{
"3": {
"id": "3",
"children": [
{
"3-1": {
"id": "3-1",
"children": []
}
}
]
}
}
]
If you notice, everything is as per expected output except the children nodes. It returns array of objects while I need object with key-value pairs. Can anybody help me with this?
You can't use map because it returns an array, you can use forEach instead, like:
function restruct(arr) {
var result = {};
arr.forEach(function(obj) {
if (obj.children) {
obj.children = restruct(obj.children);
}
result[obj.id] = obj;
});
return result;
}
function restruct(arr) {
var result = {};
arr.forEach(function(obj) {
if (obj.children) {
obj.children = restruct(obj.children);
}
result[obj.id] = obj;
});
return result;
}
Related
So I have an array of objects which have all nested children property. It is in front-end a treeview, which should expand the nodes until selected ones, for each id in a list. To be able to do this, I have to get all the parents ids for each selected id from the list.
For example, my list of checkedKeys ids:
[16787217, 16787245, 16787266, 16787270, 16787272, 16787265, 16787264]
All the checked items represents the ids from the list object:
My object list looks like this:
[
{
"id": 11,
"name": "Forecast source",
"value": null,
"children": []
},
{
"id": 2,
"name": "Item Type",
"value": null,
"children": []
},
{
"id": 16787217,
"name": "Item#Cust",
"value": null,
"children": [
{
"id": 16787230,
"name": "Customer",
"value": null,
"children": [
{
"id": 16787291,
"name": "Commercial Network",
"value": null,
"children": []
},
{
"id": 16787296,
"name": "Distribution Site",
"value": null,
"children": []
},
{
"id": 16787265,
"name": "Site",
"value": null,
"children": []
}
]
},
{
"id": 16787254,
"name": "Item",
"value": null,
"children": [
{
"id": 16787294,
"name": "ABC (Regular)",
"value": null,
"children": []
},
{
"id": 16787273,
"name": "ABC (U)",
"value": null,
"children": []
},
{
"id": 16787278,
"name": "ABC (€)",
"value": null,
"children": []
},
{
"id": 16787290,
"name": "Class",
"value": null,
"children": []
},
{
"id": 16787260,
"name": "Family",
"value": null,
"children": [
{
"id": 16787264,
"name": "Product line",
"value": null,
"children": []
}
]
},
{
"id": 16787263,
"name": "Flavour",
"value": null,
"children": []
},
{
"id": 16787262,
"name": "Format",
"value": null,
"children": []
},
{
"id": 16787261,
"name": "Group 1",
"value": null,
"children": []
},
{
"id": 16787292,
"name": "ProdGroup",
"value": null,
"children": []
},
{
"id": 16787293,
"name": "Recipe",
"value": null,
"children": []
},
{
"id": 16787288,
"name": "Sale status",
"value": null,
"children": []
}
]
},
{
"id": 16787245,
"name": "Item#Site",
"value": null,
"children": [
{
"id": 16787266,
"name": "Family#Warehouse",
"value": null,
"children": []
}
]
}
]
},
{
"id": 3,
"name": "Lead Time",
"value": null,
"children": []
},
{
"id": 5,
"name": "Levels",
"value": null,
"children": []
},
{
"id": 16787268,
"name": "N1",
"value": null,
"children": [
{
"id": 16787269,
"name": "N2",
"value": null,
"children": [
{
"id": 16787270,
"name": "N3",
"value": null,
"children": [
{
"id": 16787271,
"name": "N4",
"value": null,
"children": [
{
"id": 16787272,
"name": "N5",
"value": null,
"children": [
{
"id": 33564497,
"name": "N6",
"value": null,
"children": [
{
"id": 33564498,
"name": "N7",
"value": null,
"children": [
{
"id": 33564499,
"name": "N8",
"value": null,
"children": [
{
"id": 33564500,
"name": "N9",
"value": null,
"children": []
}
]
}
]
}
]
}
]
}
]
}
]
}
]
}
]
},
{
"id": 16787286,
"name": "Op set",
"value": null,
"children": []
}
]
So my problem is that I can't figure out how to get all parents nodes ids recursively until the root level and push them into the expandedKeys array.
I tried to implement a function like this:
this.list.forEach(el => {
this.setExpandedNodes(el);
});
setExpandedNodes(node: PropertyNode) {
if (node.children) {
node.children.forEach(chld => {
this.checkedKeys.forEach(key => {
if (chld.id === key) {
this.expandedKeys.push(node.id);
} else if (chld.children) {
chld.children.forEach(grChld => {
this.setExpandedNodes(grChld);
});
}
});
});
}
}
But I can't figure out how to get all parent ids starting from each selected id until the root level. Anyone have an idea?
Thanks to this answer I managed to do it.
getPath(model, id) {
let path,
item = model.id ;
if (!model || typeof model !== 'object') {
return;
}
if (model.id === id) {
return [item];
}
(model.children || []).some(child => (path = this.getPath(child, id)));
return path && [item, ...path];
}
setExpandedKeys() {
if (this.checkedKeys && this.checkedKeys.length > 0) {
this.checkedKeys.forEach(k => {
this.list.forEach(
mt => {
const result = this.getPath(mt, k);
if (result) {
this.expandedKeys.push(...result);
}
}
);
});
}
}
this.setExpandedKeys();
I have now all the parents ids until the root.
A function that returns an array of parent objects may look like this:
Using tree-model-js:
const getParentsById = (id, data) => {
var TreeModel = require('tree-model')
const tree = new TreeModel()
let path
for (let item of data) {
const root = tree.parse(item)
root.walk(function (node) {
// Halt the traversal by returning false
if (node.model.id === id) {
path = node.getPath()
return false;
}
});
}
path.pop()
return path.map(item => item.model)
}
Without using tree-model-js:
const getParentsById = (id, data) => {
const isFoundChild = (id, data, parents) => {
if (data.find(item => item.id == id)) {
return true;
}
else {
for (let item of data) {
if (item.children.length)
if (isFoundChild(id, item.children)) {
parents.push(item);
return true;
}
}
return false;
}
}
const parents = [];
if (data.find(item => item.id == id))
return [];
else {
for (let item of data) {
if (item.children.length)
if (isFoundChild(id, item.children, parents)) {
parents.push(item);
return parents;
}
}
}
}
Next, it is enough to apply map() to the result:
let parentsId = getParentsById(16787296, data).map(item => item.id)
In vanilla JavaScript, how would I find unique locations from this object and make them keys, and place all items with that location as values. (can install lodash if necessary).
So this:
[
{
"item": {
"id": "cat"
},
"location": {
"id": "porch"
}
},
{
"item": {
"id": "dog"
},
"location": {
"id": "porch"
}
},
{
"item": {
"id": "snake"
},
"location": {
"id": "forest"
}
},
{
"item": {
"id": "bird"
},
"location": {
"id": "forest"
}
},
{
"item": {
"id": "beer"
},
"location": {
"id": "fridge"
}
}
]
Becomes this:
[
{
"porch": [
{
"id": "cat"
},
{
"id": "dog"
}
]
},
{
"forest": [
{
"id": "snake"
},
{
"id": "bird"
}
]
},
{
"fridge": [
{
"id": "beer"
}
]
}
]
PEN
// modified desired result
[
{
"location": {
"name": "porch",
"items": [
{
"title": "cat"
},
{
"title": "dog"
}
]
}
},
{
"location": {
"name": "forest",
"items": [
{
"title": "snake"
},
{
"title": "bird"
}
]
}
},
{
"location": {
"name": "fridge",
"items": [
{
"title": "beer"
}
]
}
}
]
let obj = [
{
"item": {
"id": "cat"
},
"location": {
"id": "porch"
}
},
{
"item": {
"id": "dog"
},
"location": {
"id": "porch"
}
},
{
"item": {
"id": "snake"
},
"location": {
"id": "forest"
}
},
{
"item": {
"id": "bird"
},
"location": {
"id": "forest"
}
},
{
"item": {
"id": "beer"
},
"location": {
"id": "fridge"
}
}
]
let result = {};
obj.forEach(({item, location}) => {
if(!result[location.id]) result[location.id] = []
result[location.id].push({title: item.id})
})
result = Object.keys(result).map(key => ({
"location": {
"name": key,
"items": result[key]
}
}))
result contains required output.
I have the json Like below, i want to get the unique child sub nodes for each main nodes
{
"name": "MENUS",
"value": "",
"children": [
{
"name": "MENU1",
"value": {},
"children": [
{
"name": "SubMenu1",
"value": {},
"children": [
{
"name": "SubMenu2",
"value": {},
"children": [
{
"name": "SubMenu3",
"value": {
"Pld": "1"
},
"children": []
}
]
}
]
}
]
},
{
"name": "MENU1",
"value": {},
"children": [
{
"name": "SubMenu1",
"value": {},
"children": [
{
"name": "SubMenu2",
"value": {},
"children": [
{
"name": "SubMenu4",
"value": {
"Pld": "1"
},
"children": []
}
]
}
]
}
]
}
]
}
I wanted the JSON like below format for each main nodes i want unique sub nodes means the subnode should not be a duplicate in the JSON.
{
"name": "MENUS",
"value": "",
"children": [
{
"name": "MENU1",
"value": {},
"children": [
{
"name": "SubMenu1",
"value": {},
"children": [
{
"name": "SubMenu2",
"value": {},
"children": [
{
"name": "SubMenu3",
"value": {
"Pld": "1"
},
"children": []
},
{
"name": "SubMenu4",
"value": {
"Pld": "1"
},
"children": []
}
]
}
]
}
]
}
]
}
Could you please anyone help me how to get the unique hierarchical tree JSON.
EDIT::Adding POJO classes for reference
This is how my java pojo looks like,
MenuTree.java
private String name;
private String value;
private Children[] children;
Children.java
private String name;
private Value value;
private Children[] children;
Value.java
private String Pld;
You could use an iterative and recursive approach by searching eachlevel for existing name and append the array with new objects if not found.
var object = { name: "MENUS", value: "", children: [{ name: "MENU1", value: {}, children: [{ name: "SubMenu1", value: {}, children: [{ name: "SubMenu2", value: {}, children: [{ name: "SubMenu3", value: { Pld: "1" }, children: [] }] }] }] }, { name: "MENU1", value: {}, children: [{ name: "SubMenu1", value: {}, children: [{ name: "SubMenu2", value: {}, children: [{ name: "SubMenu4", value: { Pld: "1" }, children: [] }] }] }] }] },
unique = [object].reduce(function iter(r, { name, value, children = [] }) {
var object = r.find(o => o.name === name);
if (!object) {
object = { name, value };
r.push(object);
}
children.reduce(iter, object.children = object.children || []);
return r;
}, []);
console.log(unique);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I am getting a result in my JavaScript file which I want to convert into another object.
My original result
[
{
"SName": "Set1",
"Elements": [
{
"Id": "3",
"Name": "Name1"
},
{
"Id": "5",
"Name": "Name2"
}
]
},
{
"SName": "Set2",
"Elements": [
{
"Id": "7",
"Name": "Name3"
},
{
"Id": "8",
"Name": "Name4"
}
]
}
]
Convert this to look like array of objects using jQuery or JavaScript. How can I achieve this?
[
{
"SName": "Set1",
"Id": 3,
"Name": "Name1"
},
{
"SName": "Set1",
"Id": 5,
"Name": "Name2"
},
{
"SName": "Set2",
"Id": 7,
"Name": "Name3"
},
{
"SName": "Set2",
"Id": 8,
"Name": "Name4"
}
]
var data = [
{
"SName": "Set1",
"Elements": [
{
"Id": "3",
"Name": "Name1"
},
{
"Id": "5",
"Name": "Name2"
}
]
},
{
"SName": "Set2",
"Elements": [
{
"Id": "7",
"Name": "Name3"
},
{
"Id": "8",
"Name": "Name4"
}
]
}
];
console.log(data);
var newData = data.reduce(function (newArray, currentSet) {
return newArray.concat(currentSet.Elements.map(function (element) {
return Object.assign( { SName: currentSet.SName }, element);
}));
}, []);
console.log(newData);
The key here is the reduce function. What we are doing is creating a brand new array, by looping through each value of the outer array. We continuously concatenate onto our new array with the values we map from the inner array.
You could iterate the array, the Elements and the properties and build a new object and push it to the result set.
var array = [{ "SName": "Set1", "Elements": [{ "Id": "3", "Name": "Name1" }, { "Id": "5", "Name": "Name2" }] }, { "SName": "Set2", "Elements": [{ "Id": "7", "Name": "Name3" }, { "Id": "8", "Name": "Name4" }] }],
result = [];
array.forEach(function (a) {
a.Elements.forEach(function (b) {
var o = { SName: a.SName };
Object.keys(b).forEach(function (k) {
o[k] = b[k];
});
result.push(o);
});
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
ES6
var array = [{ "SName": "Set1", "Elements": [{ "Id": "3", "Name": "Name1" }, { "Id": "5", "Name": "Name2" }] }, { "SName": "Set2", "Elements": [{ "Id": "7", "Name": "Name3" }, { "Id": "8", "Name": "Name4" }] }],
result = [];
array.forEach(a => a.Elements.forEach(b => result.push(Object.assign({ SName: a.SName }, b))));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can do this with reduce(), forEach() and Object.assign()
var data = [{
"SName": "Set1",
"Elements": [{
"Id": "3",
"Name": "Name1"
}, {
"Id": "5",
"Name": "Name2"
}]
}, {
"SName": "Set2",
"Elements": [{
"Id": "7",
"Name": "Name3"
}, {
"Id": "8",
"Name": "Name4"
}]
}]
var result = data.reduce(function(r, e) {
e.Elements.forEach(function(o) {
r.push(Object.assign({SName: e.SName}, o))
})
return r;
}, [])
console.log(result)
Here is solution using jQuery, here is jsfiddle:
https://jsfiddle.net/noitse/3uk9qjnf/
I hope you know all key names so it wont be problem to do it fixed.
var json = [
{
"SName": "Set1",
"Elements": [
{
"Id": "3",
"Name": "Name1"
},
{
"Id": "5",
"Name": "Name2"
}
]
},
{
"SName": "Set2",
"Elements": [
{
"Id": "7",
"Name": "Name3"
},
{
"Id": "8",
"Name": "Name4"
}
]
}
]
var newJSON = []
$(json).each(function(index,value){
$(value.Elements).each(function(index1,value1){
newJSON.push({"SName":value.SName,"Id":value1.Id,"Name":value1.Name})
})
})
alert(JSON.stringify(newJSON))
Here is code , what it does it loops through first JSON , then loops through its elements , then it push it to new array
You could use the $.extend method, which lets you create a copy of an object, while merging with another object.
var source = [] // Replace with the initalization of your source array
var destination = [];
for (var i = 0; i < source.length; i++) {
var node = source[i];
for (var j = 0; j < node.Elements.length; j++) {
var subNode = node.Elements[j];
newNode = $.extend(subNode, node);
delete newNode["Elements"];
destination.push(newNode);
}
}
You can run the code in this fiddle.
I have a json array which looks something like this:
{
"id": 1,
"children": [
{
"id": 2,
"children": {
"id": 3,
"children": {
"id": 4,
"children": ""
}
}
},
{
"id": 2,
"children": {
"id": 3,
"children": {
"id": 4,
"children": ""
}
}
},
{
"id": 2,
"children": {
"id": 3,
"children": {
"id": 4,
"children": ""
}
}
},
{
"id": 2,
"children": {
"id": 3,
"children": {
"id": 4,
"children": ""
}
}
},
{
"id": 2,
"children": {
"id": 3,
"children": {
"id": 4,
"children": ""
}
}
},
{
"id": 2,
"children": {
"id": 3,
"children": {
"id": 4,
"children": ""
}
}
},
{
"id": 2,
"children": {
"id": 3,
"children": {
"id": 4,
"children": ""
}
}
}]
}
I would like to have a function which removes the elements which has the "children" empty. How can I do it? I am not asking for the answer, only suggestions
To iterate through the keys of an object, use a for .. in loop:
for (var key in json_obj) {
if (json_obj.hasOwnProperty(key)) {
// do something with `key'
}
}
To test all elements for empty children, you can use a recursive approach: iterate through all elements and recursively test their children too.
Removing a property of an object can be done by using the delete keyword:
var someObj = {
"one": 123,
"two": 345
};
var key = "one";
delete someObj[key];
console.log(someObj); // prints { "two": 345 }
Documentation:
https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Working_with_Objects
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Statements/for...in
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/delete
JSfiddle
function deleteEmpty(obj){
for(var k in obj)
if(k == "children"){
if(obj[k]){
deleteEmpty(obj[k]);
}else{
delete obj.children;
}
}
}
for(var i=0; i< a.children.length; i++){
deleteEmpty(a.children[i])
}