sorting json tree with multiple property - javascript

i have prepared a json tree from a plain json. But i need to sort the tree with multiple conditions.
for example at level 1 we have multiple objects. we need to sort with level and then with a name property.
level is a number and name is an alphanumeric. so name sorting is alphabets first and then numbers
Below is the input json
var inputJson = [
{
"level": "1",
"leafFlag": "1",
"path":"p123",
"name":"food23"
},
{
"level": "1",
"leafFlag": "1",
"path":"r125",
"name":"car1"
},
{
"level": "2",
"leafFlag": "0",
"path":"p123/p345",
"name":"apple345"
},
{
"level": "2",
"leafFlag": "1",
"path":"p123/p095",
"name":"123banana"
},
{
"level": "3",
"leafFlag": "0",
"path":"p123/p095/p546",
"name":"543"
},
{
"level": "2",
"leafFlag": "1",
"path":"r125/yhes",
"name":"tata78"
}
]
var output = [];
The below code prepares the json tree.
I tried here for sorting with multiple properties
inputJson = inputJson.sort((a, b) => (parseInt(a.level) > parseInt(b.level)) ? 1 : -1)
inputJson.forEach(v => {
if (v.level == "1") {
v.children = [];
output.push(v);
}
else {
pathValues = v.path.split("/");
pathValues.pop();
var node = null;
var fullPath = "";
pathValues.forEach(p => {
fullPath = fullPath === "" ? p : fullPath + "/" + p;
node = (node == null ? output : node.children).find(o => o.path === fullPath);
})
node.children = node.children || [];
node.children.push(v);
}
})
Output from above:
var output = [
{
"level": "1",
"leafFlag": "1",
"path": "p123",
"name": "food23",
"children": [
{
"level": "2",
"leafFlag": "0",
"path": "p123/p345",
"name": "apple"
},
{
"level": "2",
"leafFlag": "1",
"path": "p123/p095",
"name": "banana",
"children": [
{
"level": "3",
"leafFlag": "0",
"path": "p123/p095/p546",
"name": "grapes"
}
]
}
]
},
{
"level": "1",
"leafFlag": "1",
"path": "r125",
"name": "car",
"children": [
{
"level": "2",
"leafFlag": "1",
"path": "r125/yhes",
"name": "tata",
"children": [
{
"level": "3",
"leafFlag": "0",
"path": "r125/yhes/sdie",
"name": "Range Rover"
}
]
},
{
"level": "2",
"leafFlag": "0",
"path": "r125/theys",
"name": "suzuki"
}
]
}
]
Expected output:
[
{
"level": "1",
"leafFlag": "1",
"path": "r125",
"name": "car",
"children": [
{
"level": "2",
"leafFlag": "0",
"path": "r125/theys",
"name": "suzuki"
},
{
"level": "2",
"leafFlag": "1",
"path": "r125/yhes",
"name": "tata",
"children": [
{
"level": "3",
"leafFlag": "0",
"path": "r125/yhes/sdie",
"name": "Range Rover"
}
]
}
]
},
{
"level": "1",
"leafFlag": "1",
"path": "p123",
"name": "food",
"children": [
{
"level": "2",
"leafFlag": "0",
"path": "p123/p345",
"name": "apple"
},
{
"level": "2",
"leafFlag": "1",
"path": "p123/p095",
"name": "banana",
"children": [
{
"level": "3",
"leafFlag": "0",
"path": "p123/p095/p546",
"name": "grapes"
}
]
}
]
}
]
I tried something like below
inputJson = inputJson.sort((a, b) => (parseInt(a.level) > parseInt(b.level)) ? 1 : -1 && a.name > b.name ? 1 ? -1)

You could take a single sort by sorting levels first and then by name.
.sort((a, b) => a.level - b.level || a.name.localeCompare(b.name))
Then build the tree with the sorted items.
var data = [{ level: "1", leafFlag: "1", path: "p123", name: "food" }, { level: "1", leafFlag: "1", path: "r125", name: "car" }, { level: "2", leafFlag: "0", path: "p123/p345", name: "apple" }, { level: "2", leafFlag: "1", path: "p123/p095", name: "banana" }, { level: "3", leafFlag: "0", path: "p123/p095/p546", name: "grapes" }, { level: "2", leafFlag: "1", path: "r125/yhes", name: "tata" }],
result = data
.sort((a, b) => a.level - b.level || a.name.localeCompare(b.name))
.reduce((r, o) => {
let p = o.path.split('/');
p.pop();
let target = p.reduce((t, _, i, p) => {
var path = p.slice(0, i + 1).join('/'),
temp = (t.children = t.children || []).find(q => q.path === path);
if (!temp) t.children.push(temp = { path }); // this is not necessary
// if all nodes are given
return temp;
}, { children: r });
(target.children = target.children || []).push({ ...o });
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

var rootes= inputJson.filter(x=>x.level=='1')
for(i=0;i<rootes.length;i++){
rootes[i].children=[] }
var objwithchild = inputJson.filter(x=>x.leafFlag=='1')
for(i=0;i<objwithchild.length;i++){
objwithchild[i].children=[] }
inputJson.forEach(x=>{
patharr=x.path.split('/')
path=patharr.pop()
switch (x.level) {
case '2':
rootes.filter(p=>{if(p.path==patharr[0]){p.children.push(x)}
})
break
case '3':
objwithchild.filter(p=>{if(p.path==patharr[0]+'/'+patharr[1]){p.children.push(x)}
})
break
}
})
console.dir(rootes,{depth:null})

You should first sort by name, then re-sort the sorted array by level.
inputJson = inputJson.sort((a,b) => {return a.name > b.name}).sort((a,b) => {return (Number(a.level) - Number(b.level)};

Related

How to convert flat data to hierarchical JSON?

I use a fake api with this json, I still haven't been able to with this function, I need to convert the structure to look like this and I need to convert this data and then unconvert when saving
so that I change the parameters blockId to id, blockParent to parent.
{
"blocks": [
{
"blockId": "12",
"name": "Sierra",
"abrv": "Sir",
"blockParent": "0"
},
{
"blockId": "23",
"name": "Velasco",
"abrv": "Vel",
"blockParent": "12"
},
{
"blockId": "32",
"name": "UnitOne",
"abrv": "Uni",
"blockParent": "23"
},
{
"blockId": "48",
"name": "Vani",
"abrv": "Van",
"blockParent": "12"
},
{
"blockId": "57",
"name": "UnitTwo",
"abrv": "UniTwo",
"blockParent": "48"
}
]
}
const flatToTree = (blocks: IListBlocks[]) => {
const array: IListBlocks[] = []
const children: IListBlocks[] = []
blocks.forEach((block) => {
if (block.blockParent === block.blockId) {
array.push(block)
} else {
children.push(block)
}
})
array.forEach((block) => {
block.children = children.filter(
(child) => child.blockParent === block.blockId,
)
})
return array
}
{
"id": "12",
"title": "Sierra",
"subtitle": "Sir",
"parent": "0",
"children": [
{
"id": "13",
"title": "Sierra",
"subtitle": "Sir",
"parent": "12",
}
]
}

Add an Array to an JSON Object

In my API im receiving a JSON with 2 arrays, one Employees and another with Managers, the goal is to add the Managers to each Employee, knowing that the 1st index of the managers corresponds to the 1st index of the employees and so on:
This is an example of the request to the API
{
"employees" : [ {
"code" : "111111",
"name" : "Zé"
},
{
"code" : "222222",
"name" : "João"
},
{
"code" : "444444",
"name" : "António"
}],
"managers" : [
[
{
"name": "vitor",
"level" : "1"
},
{
"name": "Antonio",
"level" : "2"
}
],
[
{
"name": "Jose",
"level" : "1"
},
{
"name": "Ines",
"level" : "2"
}
],
[
{
"name": "Luis",
"level" : "1"
},
{
"name": "Ana",
"level" : "2"
}
]
]
}
and my goal is to get something like this:
[
{
"code": "111111",
"name": "Zé",
"managers": [
{
"name": "vitor",
"level": "1"
},
{
"name": "Antonio",
"level": "2"
}
]
},
{
"code": "222222",
"name": "João",
"managers": [
{
"name": "Jose",
"level": "1"
},
{
"name": "Ines",
"level": "2"
}
]
},
{
"code": "444444",
"name": "António",
"managers": [
{
"name": "Jose",
"level": "1"
},
{
"name": "Ines",
"level": "2"
}
]
}
]
I already tried some things but i can't get the expected result :(
Hope you can help me!! Thanks
function associate_employee_managers({ employees, managers }) {
return employees && employees.length
&& employees
.map((emp, index) => {
return {
...emp,
["managers"]: managers && managers[index] || []
};
}) || {};
}
Considerations
There is 1-1 correspondence(based on index) between entries inside employees array and managers array
Illustration
function associate_employee_managers({
employees,
managers
}) {
return employees && employees.length &&
employees
.map((emp, index) => {
return {
...emp,
["managers"]: managers && managers[index] || []
};
}) || {};
}
const jsonResponse = {
"employees": [{
"code": "111111",
"name": "Zé"
},
{
"code": "222222",
"name": "João"
},
{
"code": "444444",
"name": "António"
}
],
"managers": [
[{
"name": "vitor",
"level": "1"
},
{
"name": "Antonio",
"level": "2"
}
],
[{
"name": "Jose",
"level": "1"
},
{
"name": "Ines",
"level": "2"
}
],
[{
"name": "Luis",
"level": "1"
},
{
"name": "Ana",
"level": "2"
}
]
]
}
console.log(associate_employee_managers(jsonResponse));
WYSIWYG => WHAT YOU SHOW IS WHAT YOU GET

Get value from key of parent and pass it to children key in object

I have structure like below:
{
0: [{
"id": "1",
"parentId": "root",
"path": "root"
"children": [{
"id": "2",
"parentId": "1",
"path": "1/2",
"children": [
"id": "4",
"parentId": "2",
"path": "2/4"
]
}, {
"id": "3",
"parentId": "1",
"path": "1/3"
}]
}]
}
I have key "path" and now it's "parentId/id", but I would like to have path from root to this element, so it should looks "root/parentId/id/parentId/it..." etc. For example path: "root/1/2/4".
How can I dynamically put a value inside key "path" to get full path to root element?
Your data structure does not respect the childhood of each element, but considering this is not a part of the question, here is a simple recursive solution:
const data = [{
"id": "1",
"parentId": "root",
"path": "root",
"children": [{
"id": "2",
"parentId": "1",
"path": "1/2",
"children": [{
"id": "4",
"parentId": "2",
"path": "2/4"
}
]
}, {
"id": "3",
"parentId": "1",
"path": "1/3"
}
]
},
{
"id": "4",
"parentId": "2",
"path": "2/4"
}
];
function assignPath(tree, index, array, currentPath) {
tree.path = currentPath || 'root';
tree.children && tree.children.forEach(child => {
assignPath(child, null, null, `${tree.path}/${child.id}`);
});
}
data.forEach(assignPath);
console.log(data);
You will need to identify the root node and start with its path.
Then add each consecutive child id to the path end.
let obj = {
0: [{
"id": "1",
"parentId": "root",
"path": "root",
"children": [{
"id": "2",
"parentId": "1",
"path": "1/2",
"children": [{
"id": "4",
"parentId": "2",
"path": "2/4"
}]
}, {
"id": "3",
"parentId": "1",
"path": "1/3"
}]
}]
};
console.log(getRoute(obj[0][0], true)); // Identify root
function getRoute(node, isRoot) {
return node != null
? (isRoot
? (node.path + '/')
: ''
) + node.id + (node.children
? '/' + getRoute(node.children[0], false)
: '')
: '';
}
Recursive solution:
updatePath(array, 'root');
function updatePath(array, path) {
array.forEach((element, i) => {
element.path = path + '/' + (i + 1);
if(element.hasOwnProperty('children')) {
updatePath(element.children, element.path);
}
});
}

Create new javascript object from 2 JSON objects grouped by id

I have below dynamic nested JSON object arrays and I wanted to get the desired output with JavaScript grouped by id from both.
First Array:
[
{
"id": "11",
"name": "emp1",
"location": [
{ "name": "abc", "id": "lc1" }
]
},
{
"id": "11",
"name": "emp2",
"location": [
{ "name": "abc", "id": "lc1" },
]
},
{
"id": "22",
"name": "emp3",
"location": [
{ "name": "xyz", "id": "lc2" }
]
}
]
Second array like below.
[
{
"name": "sub1",
"id": "11"
...
},
{
"name": "sub1.1",
"id": "11"
...
},
{
"name": "sub2",
"id": "22"
...
}
]
Desired Output:
[
{
"id": "11",
"first": [{"name": "emp1"},
{"name": "emp2"}],
"second": [{"name": "sub1"},{"name": "sub1.1"}],
"location": [{"name": "abc"}]
},
{
"id": "22",
"first": [{"name": "emp3"}],
"second": [{"name": "sub2"}],
"location": [{"name": "xyz"}]
}
]
How to get the desired output like above using javascript/angularjs?
I would do it using the amazing Array#reduce function.
Note that I have named your first array as a1, second as a2 and result as res.
a1.reduce(function(arr, obj) {
var existing = arr.filter(function(res) {
return res.id === obj.id
})[0]
if (existing) {
existing.first.push({
name: obj.name
})
} else {
var second = a2.filter(function(res) {
return res.id === obj.id
})
var secondObj = second.length ? second.map(function(sec) {
return {
name: sec.name
};
}) : []
arr.push({
id: obj.id,
first: [{
name: obj.name
}],
second: secondObj,
location: obj.location
})
}
return arr;
}, [])
Here's the working snippet. Take a look!
var a1 = [{
"id": "11",
"name": "emp1",
"location": [{
"name": "abc",
"id": "lc1"
}]
},
{
"id": "11",
"name": "emp2",
"location": [{
"name": "abc",
"id": "lc1"
}]
},
{
"id": "22",
"name": "emp3",
"location": [{
"name": "xyz",
"id": "lc2"
}]
}
]
var a2 = [{
"name": "sub1",
"id": "11"
}, {
"name": "sub1.1",
"id": "11"
},
{
"name": "sub2",
"id": "22"
}
]
var res = a1.reduce(function(arr, obj) {
var existing = arr.filter(function(res) {
return res.id === obj.id
})[0]
if (existing) {
existing.first.push({
name: obj.name
})
} else {
var second = a2.filter(function(res) {
return res.id === obj.id
})
var secondObj = second.length ? second.map(function(sec) {
return {
name: sec.name
};
}) : []
arr.push({
id: obj.id,
first: [{
name: obj.name
}],
second: secondObj,
location: obj.location
})
}
return arr;
}, [])
console.log(res)
.as-console-wrapper {
max-height: 100% !important;
top: 0;
}
var red1 = [{
"id": "11",
"name": "emp1",
"location": [{
"name": "abc",
"id": "lc1"
}]
},
{
"id": "11",
"name": "emp2",
"location": [{
"name": "abc",
"id": "lc1"
}]
},
{
"id": "22",
"name": "emp3",
"location": [{
"name": "xyz",
"id": "lc2"
}]
}
]
var b = [{
"name": "sub1",
"id": "11"
},
{
"name": "sub2",
"id": "22"
}
]
var identication = {}
var result = []
red1.forEach(function(val) {
if (val['id'] in identication) {
var t = {}
t['name'] = val['name']
result[identication[val['id']]]['first'].push(t)
} else {
var t = {}
t['name'] = val['name']
val['first'] = []
val['first'].push(t)
delete val['name']
var identity = result.push(val)
identication[val['id']] = identity - 1;
}
})
b.forEach(function(d) {
if (d['id'] in identication) {
var t = {
'name': d['name']
}
if (!('second' in result[identication[d['id']]])) {
result[identication[d['id']]]['second'] = []
}
result[identication[d['id']]]['second'].push(t)
} else {
var t = {}
for (key in d) {
if (key == 'name')
continue
t[key] = d[key]
}
t['second'] = [{
'name': d['name']
}]
var identity = result.push(t)
identication[d['id']] = identity - 1;
}
})
console.log(result)

Jquery : transform nested json object to another json object

In javascript/jquery how do i achieve following
old_dataset = [
{
"dob": "xyz",
"name": {
"first": " abc",
"last": "lastname"
},
"start_date": {
"moth": "2",
"day": "5",
"year": 1
},
"children": [
{
"child": {
"id": "1",
"desc": "first child"
}
},
{
"child": {
"id": "2",
"desc": "second child"
}
}
]
},
{
"dob": "er",
"name": {
"first": " abc",
"last": "txt"
},
"start_date": {
"moth": "2",
"day": "5",
"year": 1
},
"children": [
{
"child": {
"id": "1",
"desc": "first child"
}
},
{
"child": {
"id": "2",
"desc": "second child"
}
}
]
}
]
Using jquery iterate over the above and change to following
new_dataset = [
{
"dob":"xyz",
"name": <first and last name values>
"start_date":<value of month day year>,
"children": [ {
child_id :1,
child_id : 2
},
]
},{
"dob":"er",
"name": <first and last name values>
"start_date":<value of month day year>,
"children": [ {
child_id :1,
child_id : 2
},
]
}]
If someone can give the code to transform the data it would help me to understand the iteration
You could do something like:
function transformDataset(oldDataset) {
var newDataset = [];
var newObj;
for (var i = 0; i < oldDataset.length; i++) {
newObj = transformObj(oldDataset[i]);
newDataset.push(newObj);
}
return newDataset;
}
function transformObj(obj) {
var children = obj.children;
obj.name = obj.name.first + ' ' + obj.name.last;
obj.start_date = obj.start_date.month + ' ' + obj.start_date.day + ' ' + obj.start_date.year;
obj.children = [];
for (var i = 0; i < children.length; i++) {
obj.children.push(children[i].child.id);
}
return obj;
}
var new_dataset = transformDataset(old_dataset);
Note that new_dataset will have an array of child id instead of an object with multiple child_id properties.
You also had a typo in old_dataset.start_date.month (was written moth)(or maybe that was intentional).
use map first to iterate the array data (old_dataset), replace element name & start_date with new value then return the array
const old_dataset = [
{
"dob": "xyz",
"name": {
"first": " abc",
"last": "lastname"
},
"start_date": {
"moth": "2",
"day": "5",
"year": 1
},
"children": [
{
"child": {
"id": "1",
"desc": "first child"
}
},
{
"child": {
"id": "2",
"desc": "second child"
}
}
]
},
{
"dob": "er",
"name": {
"first": " abc",
"last": "txt"
},
"start_date": {
"moth": "2",
"day": "5",
"year": 1
},
"children": [
{
"child": {
"id": "1",
"desc": "first child"
}
},
{
"child": {
"id": "2",
"desc": "second child"
}
}
]
}
]
let new_dataset = old_dataset.map((arr) => {
arr.name = `${arr.name.first} ${arr.name.last}`
arr.start_date = `${arr.start_date.moth} ${arr.start_date.day} ${arr.start_date.year}`
return arr
})
console.log(new_dataset)

Categories

Resources