Reverse level of treeview javascript - javascript

Please help me out to create treeview by javascript array. The scenario is I want to create treeview with reverse level.
For Example:
I have an array in below format:
var arr = [
{'id':1 ,'parentid' : 0},
{'id':2 ,'parentid' : 1},
{'id':3 ,'parentid' : 1},
{'id':4 ,'parentid' : 2},
{'id':5 ,'parentid' : 0},
{'id':6 ,'parentid' : 0},
{'id':7 ,'parentid' : 4}
];
and I am trying to create treeview in below order:
Expected output:
[
{
"id": 1,
"parentid": 0,
level:4,
"children": [
{
"id": 2,
"parentid": 1,
level:3,
"children": [
{
"id": 4,
"parentid": 2,
level:2,
"children": [
{
"id": 7,
"parentid": 4,
level:1
}
]
}
]
},
{
"id": 3,
"parentid": 1,
level:3
}
]
},
{
"id": 5,
"parentid": 0
level:4
},
{
"id": 6,
"parentid": 0,
level:4
}
]

Basically the task is solved in three steps
build tree
get the maximal level
apply the level
var arr = [{ 'id': 1, 'parentid': 0 }, { 'id': 2, 'parentid': 1 }, { 'id': 3, 'parentid': 1 }, { 'id': 4, 'parentid': 2 }, { 'id': 5, 'parentid': 0 }, { 'id': 6, 'parentid': 0 }, { 'id': 7, 'parentid': 4 }],
tree = function (array) {
function iterGet(o) {
if (Array.isArray(o.children)) {
maxLevel++;
o.children.forEach(iterGet);
}
}
function iterSet(level) {
return function (o) {
o.level = level;
Array.isArray(o.children) && o.children.forEach(iterSet(level - 1));
}
}
var o = { id: 0 },
maxLevel = 1;
array.forEach(function (a) {
o[a.id] = o[a.id] || { id: a.id };
a.children = o[a.id].children;
o[a.parentid] = o[a.parentid] || { id: a.parentid };
o[a.parentid].children = o[a.parentid].children || [];
o[a.parentid].children.push(o[a.id]);
});
iterGet(o[0]);
iterSet(maxLevel)(o[0]);
return o[0].children;
}(arr);
document.write('<pre>' + JSON.stringify(tree, 0, 4) + '</pre>');

Related

Filter array object by name

I have array object like this, can you help me?
[{id: 1, name: "contractor"},
{id: 2, name: "owner", },
{id: 3, name: "manager", },
{id: 4, name: "customer", },
{id: 5, name: "admin",}]
I want a format like that:
if admin
[admin:
{id: 1, name: "contractor"},
{id: 2, name: "owner", },
{id: 3, name: "manager", },
{id: 4, name: "customer", }]
if contractor
[contractor:
{id: 2, name: "owner", },
{id: 3, name: "manager", },
{id: 4, name: "customer", }]
if owner
[owner:
{id: 3, name: "manager", },
{id: 4, name: "customer", }]
if manager
[manager:
{id: 4, name: "customer", }]
Based on the comments, i guess you need this
let array = [
{id: 1, name: "contractor"},
{id: 2, name: "owner"},
{id: 3, name: "manager"},
{id: 4, name: "customer"},
{id: 5, name: "admin"}
]
const admin = { admin: array.filter(obj => obj.id < 5) }
const contractor = { contractor: array.filter(obj => [2, 3, 4].includes(obj.id)) }
const owner = { owner: array.filter(obj => [3, 4].includes(obj.id)) }
const manager = { manager: array.filter(obj => obj.id === 4) }
console.log(admin, contractor, owner, manager)
IF you want to make it so it will only generate the array if it is included in the name, then you can use array.reduce
const array = [
{id: 1, name: "contractor"},
{id: 2, name: "owner"},
{id: 3, name: "manager"},
{id: 4, name: "customer"},
{id: 5, name: "admin"}
];
const objects = array.reduce((prev, curr) => {
if (prev[curr.name]) {
return {
...prev,
[prev[curr.name]]: prev[curr.name].concat(curr),
}
}
return {
...prev,
[curr.name]: [curr]
}
}, {});
console.log(objects);
You have to sort the data first, as you can see the below code. I hope this would be helpful. thanks
const array = [
{ id: 1, name: "contractor", sort: 2 },
{ id: 2, name: "owner", sort: 3 },
{ id: 3, name: "manager", sort: 4 },
{ id: 4, name: "customer", sort: 5 },
{ id: 5, name: "admin", sort: 1 }
];
let nameArr = [];
let arr = [];
let newArray = [];
const sortedData = array.sort((a, b) => a.sort - b.sort);
sortedData.forEach(ele => {
array.forEach(item => {
if (item.name !== ele.name) {
if (newArray.length) {
if (!nameArr.includes(item.name) && (item.name !== ele.name)) {
arr.push(item);
}
} else {
arr.push(item);
}
}
})
newArray.push({ [ele.name]: arr });
nameArr.push(ele.name);
arr = []
})
console.log(newArray)
Result will be this:
[
{
"admin": [
{
"id": 1,
"name": "contractor",
"sort": 2
},
{
"id": 2,
"name": "owner",
"sort": 3
},
{
"id": 3,
"name": "manager",
"sort": 4
},
{
"id": 4,
"name": "customer",
"sort": 5
}
]
},
{
"contractor": [
{
"id": 2,
"name": "owner",
"sort": 3
},
{
"id": 3,
"name": "manager",
"sort": 4
},
{
"id": 4,
"name": "customer",
"sort": 5
}
]
},
{
"owner": [
{
"id": 3,
"name": "manager",
"sort": 4
},
{
"id": 4,
"name": "customer",
"sort": 5
}
]
},
{
"manager": [
{
"id": 4,
"name": "customer",
"sort": 5
}
]
},
{
"customer": []
}
]

How to group values from an array of objects by same values with javascript?

I have an array of objects as following
[
0: {department_ID: 6, department_Name: "Management", section_ID: 12, section_Name: "General Management", employee_ID: 1, …}
1: {department_ID: 6, department_Name: "Management", section_ID: 12, section_Name: "General Management", employee_ID: 2, …}
2: {department_ID: 1, department_Name: "HR & Admin", section_ID: 20, section_Name: "HR and Admin", employee_ID: 90, …}
...
]
What I want to achieve is to group values in an array by order same department_ID > same section_ID and finally employee data like this
[
{
department_ID: 6,
department_Name: "Management",
children: [
{
section_ID: 12,
section_Name: "General Management",
children: [
{
employee_ID: 1,
employee_Name: "",
},
{
employee_ID: 2,
employee_Name: "",
},
],
},
],
},
{
department_ID: 1,
department_Name: "HR & Admin",
children: [
{
section_ID: 20,
section_Name: "HR and Admin",
children: [
{
employee_ID: 90,
employee_Name: "",
},
],
},
],
},
];
I've tried
function getUnique() {
var hashObject = {};
let obj = {};
treeviewApiValues.forEach(function (elem) {
var key = elem.department_ID;
if (hashObject[key]) {
hashObject[key] = {
id: elem.department_ID,
name: elem.department_Name,
children: checkSectionID(elem),
};
} else {
hashObject[key] = {
id: elem.department_ID,
name: elem.department_Name,
children: checkSectionID(elem),
};
}
});
function checkSectionID(elem) {
const key = elem.department_ID;
if (obj[key]) {
obj[key].push({
id: elem.section_ID,
name: elem.section_Name,
});
} else {
obj[key] = [
{
id: elem.section_ID,
name: elem.section_Name,
},
];
}
var desiredArray2 = Object.values(obj);
return desiredArray2;
}
var desiredArray = Object.values(hashObject);
}
This is a messy function, but I get
[
0: {department_ID: 1, department_Name: "HR & Admin", children: Array(7)}
1: {department_ID: 2, department_Name: "ELV Systems Installation & Service", children: Array(7)}
]
Children array is something wrong and not having array of same department_ID and I also need to get the employee data under same section_ID.
If anyone could help me, i would be so much appreciated.
Full code can be found here https://codesandbox.io/s/gracious-voice-bbmsy?file=/src/App.js
You could take a nested approach with an array for the grouping levels.
This solution removes unwanted properties from the object and pushes the final object to the most nested children array.
This solution works for an arbitrary count of levels.
const
data = [{ department_ID: 6, department_Name: "Management", section_ID: 12, section_Name: "General Management", employee_ID: 1 }, { department_ID: 6, department_Name: "Management", section_ID: 12, section_Name: "General Management", employee_ID: 2 }, { department_ID: 1, department_Name: "HR & Admin", section_ID: 20, section_Name: "HR and Admin", employee_ID: 90 }],
groups = [['department_ID', 'department_Name'], ['section_ID', 'section_Name']],
result = data.reduce((r, o) => {
groups
.reduce((group, keys) => {
let temp = group.find(q => q[keys[0]] === o[keys[0]]);
if (!temp) group.push(temp = { ...Object.fromEntries(keys.map(k => [k, o[k]])), children: [] });
keys.forEach(k => ({ [k]: _, ...o} = o));
return temp.children;
}, r)
.push(o);
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
May be it solve your task
let list = [
{department_ID: 6, department_Name: "Management", section_ID: 12, section_Name: "General Management", employee_ID: 1, …},
{department_ID: 6, department_Name: "Management", section_ID: 12, section_Name: "General Management", employee_ID: 2, …},
{department_ID: 1, department_Name: "HR & Admin", section_ID: 20, section_Name: "HR and Admin", employee_ID: 90, …}
...
];
let vals = [];
list.map(v=>{
vals[v.department_ID] || (vals[v.department_ID] = {
department_ID: v.department_ID,
department_Name: v.department_Name,
children: []
});
vals[v.department_ID].children[v.section_ID] ||
(vals[v.department_ID].children[v.section_ID] = {
section_ID: v.section_ID,
section_Name: v.section_Name,
children: []
});
vals[v.department_ID].children[v.section_ID].children.push({
employee_ID: v.employee_ID,
employee_Name: v.employee_Name
});
});
vals = vals.filter(e=>!!e);
let result = vals.map(e=>{
e.children = e.children.filter(v=>!!v);
return e;
});
You can use reduce() and find() as follows:
const arr = [
{department_ID: 6, department_Name: "Management", section_ID: 12, section_Name: "General Management", employee_ID: 1, employee_name: 'john'},
{department_ID: 6, department_Name: "Management", section_ID: 12, section_Name: "General Management", employee_ID: 2, employee_name: 'avi'},
{department_ID: 1, department_Name: "HR & Admin", section_ID: 20, section_Name: "HR and Admin", employee_ID: 90, employee_name: 'jennifer'}
]
const res = arr.reduce((acc, curr) => {
const obj = acc.find(item => item.department_ID === curr.department_ID && item?.children[0]?.section_ID === curr.section_ID);
if(obj) {
obj.children[0].children.push({ employee_ID: curr.employee_ID, employee_name: curr.employee_name});
} else {
acc.push({
department_ID: curr.department_ID,
department_Name: curr.department_Name,
children: [
{
section_ID: curr.section_ID,
section_Name: curr.section_Name,
children: [{
employee_ID: curr.employee_ID,
employee_name: curr.employee_name
}]
}
]
})
}
return acc;
}, []);
console.log(res);

Javascript creates new arrays based on conditions

I have old and entity arrays:
var old = [
{
"id": 3,
"entity_type_id": 1,
"product_id": 4,
"name": "test1",
"acreage": 100,
"yield": 20,
"worth": 30
},
{
"id": 4,
"entity_type_id": 1,
"product_id": 4,
"name": "test2",
"acreage": 10,
"yield": 20,
"worth": 0
},
{
"id": 5,
"entity_type_id": 3,
"product_id": 5,
"name": "test3",
"acreage": 20,
"yield": 20,
"worth": 40
}
]
var entity = [
{"id": 1, "name": "a1"},
{"id": 2, "name": "a2"},
{"id": 3, "name": "a3"}
]
I hope to get the following data:
var newArr = [
{
"id": 3,
"entity_type_id": 1,
"product_id": 4,
"name": "test1",
"acreage": 110,
"yield": 40,
"worth": 30,
"entity_type_1": 2, // The total amount of entity_type_id (entity_type_id: 1)
"entity_type_2": 0,
"entity_type_3": 0
},
{
"id": 5,
"entity_type_id": 3,
"product_id": 5,
"name": "test3",
"acreage": 20,
"yield": 20,
"worth": 40,
"entity_type_1": 0,
"entity_type_2": 0,
"entity_type_3": 1 // The total amount of entity_type_id (entity_type_id: 3)
}
]
console.log(newArr)
I tried the following code and got some data. I'm not sure if there will be any exceptions or errors.
What's more, I don't know how to deal with the entity array data. Can someone help me solve this problem and get the result I expect?
Thank you very much !
function mergeArr(arr) {
const temp = []
arr.forEach((dataItem) => {
if (temp.length) {
let filterValue = temp.filter((items) => {
return items.product_id === dataItem.product_id
})
if (filterValue.length) {
temp.forEach((n) => {
if (n.product_id === filterValue[0].product_id) {
n.yield = dataItem.yield + filterValue[0].yield
n.acreage = dataItem.acreage + filterValue[0].acreage
n.worth = dataItem.worth + filterValue[0].worth
}
})
} else {
temp.push(dataItem)
}
} else {
temp.push(dataItem)
}
})
return temp
}
Youi could find the object and sum the wanted properties. For entity take another loop and map new entries and build a new object from it for spreading.
var old = [{ id: 3, entity_type_id: 1, product_id: 4, name: "test1", acreage: 100, yield: 20, worth: 30 }, { id: 4, entity_type_id: 1, product_id: 4, name: "test2", acreage: 10, yield: 20, worth: 0 }, { id: 5, entity_type_id: 3, product_id: 5, name: "test3", acreage: 20, yield: 20, worth: 40 }],
entity = [{ id: 1, name: "a1" }, { id: 2, name: "a2" }, { id: 3, name: "a3" }],
entityTypes = Object.fromEntries(entity.map(({ id }) => ['entity_type_' + id, 0])),
result = old.reduce((r, o) => {
let temp = r.find(q => q.product_id === o.product_id);
if (!temp) r.push(temp = { ... o, ...entityTypes });
else ['acreage', 'yield', 'worth'].forEach(k => temp[k] += o[k]);
temp['entity_type_' + o.entity_type_id]++;
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

JS Loop through array based on key values and add values

I have the following object inside an array:-
[
{"score": 5, "question": 0, "weight": 2},
{"score": 4, "question": 1, "weight": 2},
{"score": 3, "question": 0, "weight": 4},
{"score": 4, "question": 1, "weight": 4},
{"score": 2, "question": 2, "weight": 4},
{"score": 8, "question": 0, "weight": 2}
]
I am trying to loop through the array so I have the following output, so I am able to run some math against the results:-
[
[
{"score": 5, "question": 0, "weight": 2},
{"score": 4, "question": 1, "weight": 2}
],
[
{"score": 3, "question": 0, "weight": 4},
{"score": 4, "question": 1, "weight": 4},
{"score": 2, "question": 2, "weight": 4}
],
[
{"score": 8, "question": 0, "weight": 2}
]
];
Is there a dynamic way I am able to get array1 to look like array2?
I am using flat JS for this please no jQuery answers.
Thanks in advance.
** Note **
Sometimes each section will have more or less values, this is why I require it to be dynamic.
You can do this with reduce() method you just need to keep track of current index for final array.
const data =[
{score: 5, question: 0, weight: 2},
{score: 4, question: 1, weight: 2},
{score: 3, question: 0, weight: 4},
{score: 4, question: 1, weight: 4},
{score: 2, question: 2, weight: 4},
{score: 8, question: 0, weight: 2}
]
const result = data.reduce(function(r, e, i) {
if(i == 0) r = {values: [], counter: 0}
if(e.question == 0 && i != 0) r.counter++
if(!r.values[r.counter]) r.values[r.counter] = [e]
else r.values[r.counter].push(e)
return r;
}, {}).values
console.log(result)
You could check weight and if different, then take a new group.
var data = [{ score: 5, question: 0, weight: 2 }, { score: 4, question: 1, weight: 2 }, { score: 3, question: 0, weight: 4 }, { score: 4, question: 1, weight: 4 }, { score: 2, question: 2, weight: 4 }, { score: 8, question: 0, weight: 2 }],
grouped = data.reduce(function (r, o, i, a) {
if ((a[i - 1] || {}).weight !== o.weight) {
r.push([]);
}
r[r.length - 1].push(o);
return r;
}, []);
console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use Array.reduce() to convert the 1st to the 2nd array. Whenever the current object weight doesn't match lastWeight, add another subarray. Always push the current item to the last subarray:
const arr = [
{score: 5, question: 0, weight: 2},
{score: 4, question: 1, weight: 2},
{score: 3, question: 0, weight: 4},
{score: 4, question: 1, weight: 4},
{score: 2, question: 2, weight: 4},
{score: 8, question: 0, weight: 2}
];
let lastWeight = null;
const result = arr.reduce((r, o) => {
if(lastWeight === null || o.weight !== lastWeight) {
lastWeight = o.weight;
r.push([]);
}
r[r.length - 1].push(o);
return r;
}, []);
console.log(result);
var oldA = [
{"score": 5, "question": 0, "weight": 2},
{"score": 4, "question": 1, "weight": 2},
{"score": 3, "question": 0, "weight": 4},
{"score": 4, "question": 1, "weight": 4},
{"score": 2, "question": 2, "weight": 4},
{"score": 8, "question": 0, "weight": 2}
];
var newA = [];
var prevW = 0;
var prevA;
for (var i = 0; i < oldA.length; i++) {
if (oldA[i].weight != prevW) {
prevA = [];
newA.push(prevA);
prevW = oldA[i].weight;
}
prevA.push(oldA[i]);
}
console.log(newA);
You can use array#reduce to group your array. Check if the value of question is 0 then push a new array and add the object to it.
var data = [ {"score": 5, "question": 0, "weight": 2}, {"score": 4, "question": 1, "weight": 2}, {"score": 3, "question": 0, "weight": 4}, {"score": 4, "question": 1, "weight": 4}, {"score": 2, "question": 2, "weight": 4}, {"score": 8, "question": 0, "weight": 2}],
result = data.reduce((r,o) => {
if(o.question == 0)
r.push([]);
r[r.length - 1].push(o);
return r;
},[]);
console.log(result);
let scores = [
{"score": 5, "question": 0, "weight": 2},
{"score": 4, "question": 1, "weight": 2},
{"score": 3, "question": 0, "weight": 4},
{"score": 4, "question": 1, "weight": 4},
{"score": 2, "question": 2, "weight": 4},
{"score": 8, "question": 0, "weight": 2}
]
let groupedScores = [], group = [];
scores.forEach((entry) => {
if(entry.question === 0) {
if (group.length) {
groupedScores.push(group);
}
group = [];
}
group.push(entry);
})
groupedScores.push(group)
console.log(groupedScores)
A bit simplified if splitting by just question: 0 :
data = [ { score: 5, question: 0, weight: 2 }, { score: 4, question: 1, weight: 2 },
{ score: 3, question: 0, weight: 4 }, { score: 4, question: 1, weight: 4 },
{ score: 2, question: 2, weight: 4 }, { score: 8, question: 0, weight: 2 } ]
result = data.reduce((r, v) => (v.question ? r[r.length-1].push(v) : r.push([v]), r), [])
console.log( result )

lodash merge and combine objects

I have an array of objects as below that I read from my database using sequelize ORM:
I want to have all my videos from a section, but the better I can return using sequelize is :
[{
"id": 2,
"name": "Ru",
"subsection": 1,
"Video": {
"id": 11,
"source": "sourrrccrsss22222",
"videoSubSection": 2
}
},
{
"id": 2,
"name": "Ru",
"subsection": 1,
"Video": {
"id": 12,
"source": "sourrrccrsss111",
"videoSubSection": 2
}
},
{
"id": 1,
"name": "Oc",
"subsection": 1,
"Video": {
"id": 13,
"source": "sourrrcc",
"videoSubSection": 1
}
},
{
"id": 1,
"name": "Oc",
"subsection": 1,
"Video": {
"id": 14,
"source": "sourrrcc",
"videoSubSection": 1
}
}]
Is there a way to merge and combine the objects in my array to obtain something like this :
[{
"id": 2,
"name": "Ru",
"subsection": 1,
"Video": [{
"id": 11,
"source": "sourrrccrsss22222",
"videoSubSection": 2
},{
"id": 12,
"source": "sourrrccrsss111",
"videoSubSection": 2
}]
},
{
"id": 1,
"name": "Oc",
"subsection": 1,
"Video": [{
"id": 13,
"source": "sourrrcc",
"videoSubSection": 1
},{
"id": 14,
"source": "sourrrcc",
"videoSubSection": 1
}]
}
The function that approach the most is _.mergeWith(object, sources, customizer) but the main problem I have is that I have on object and need to merge this object.
In plain Javascript, you can use Array#forEach() with a temporary object for the arrays.
var data = [{ id: 2, name: "Ru", subsection: 1, Video: { id: 11, source: "sourrrccrsss22222", VideoSubSection: 2 } }, { id: 2, name: "Ru", subsection: 1, Video: { id: 12, source: "sourrrccrsss111", VideoSubSection: 2 } }, { id: 1, name: "Oc", subsection: 1, Video: { id: 13, source: "sourrrcc", VideoSubSection: 1 } }, { id: 1, name: "Oc", subsection: 1, Video: { id: 14, source: "sourrrcc", VideoSubSection: 1 } }],
merged = function (data) {
var r = [], o = {};
data.forEach(function (a) {
if (!(a.id in o)) {
o[a.id] = [];
r.push({ id: a.id, name: a.name, subsection: a.subsection, Video: o[a.id] });
}
o[a.id].push(a.Video);
});
return r;
}(data);
document.write('<pre>' + JSON.stringify(merged, 0, 4) + '</pre>');
Maybe try transform():
_.transform(data, (result, item) => {
let found;
if ((found = _.find(result, { id: item.id }))) {
found.Video.push(item.Video);
} else {
result.push(_.defaults({ Video: [ item.Video ] }, item));
}
}, []);
Using reduce() would work here as well, but transform() is less verbose.
You can do it this way (test is your db output here)
var result = [];
var map = [];
_.forEach(test, (o) => {
var temp = _.clone(o);
delete o.Video;
if (!_.some(map, o)) {
result.push(_.extend(o, {Video: [temp.Video]}));
map.push(o);
} else {
var index = _.findIndex(map, o);
result[index].Video.push(temp.Video);
}
});
console.log(result); // outputs what you want.

Categories

Resources