lodash groupby key if exist in collection - javascript

I have below an array
{
"sec": "11",
"details": [
{
"id": "1",
"user": "Me1"
},
{
"id": "2",
"uesr": "Me2"
},
{
"id": "3",
"user": "Me3"
}
{
"id": "4",
"user": "Me4",
parentID:"2"
},
{
"id": "5",
"uesr": "Me5"
},
{
"id": "6",
"user": "Me6",
parentID:"2"
}
{
"id": "7",
"user": "Me7"
},
{
"id": "8",
"uesr": "Me8",
parentID:"7"
},
{
"id": "9",
"user": "Me9",
parentID:"7"
}
],
"isDisplay": "true"
}
and output should be like below
{
"sec":"11",
"details":[
{
"id":"1",
"user":"Me1"
},
{
"id":"2",
"uesr":"Me2",
"childs":[
{
"id":"4",
"user":"Me4",
"parentID":"2"
},
{
"id":"6",
"user":"Me6",
"parentID":"2"
}
]
},
{
"id":"3",
"user":"Me3"
},
{
"id":"5",
"uesr":"Me5"
},
{
"id":"7",
"user":"Me7",
"childs":[
{
"id":"8",
"uesr":"Me8",
"parentID":"7"
},
{
"id":"9",
"user":"Me9",
"parentID":"7"
}
]
}
],
"isDisplay":"true"
}
I can do this by simple looping,
In lodash or anything angular does this functionality.
I am clueless to start,
I just give below code
this.list = _.groupBy(this.list,"parentID");
But the output not as expected.
Please help or guide
Thanks

You need a different approach, not grouping, but creating a tree out of the related data.
This solution uses an array with id as key and with parentID as well. The code works with a single loop, because of storing of the relation of children and parent and parent to their children.
How it works:
Basically for every object in the array it takes as well the id for building a new object as the parentID for a new object.
So for example this object
{ id: "6", parentID: "2", user: "Me6" }
it generates in o first with id this property
6: {
id: "6",
parentID: "2",
user: "Me6"
}
and then this property with parentID
2: {
children: [
{
id: "6",
parentID: "2",
user: "Me6"
}
]
},
and while all object treated like this, we finally get a tree.
At the end, the children array of the root property is returned.
function getTree(data, root) {
var o = {};
data.forEach(function (a) {
if (o[a.id] && o[a.id].children) {
a.children = o[a.id].children;
}
o[a.id] = a;
o[a.parentID] = o[a.parentID] || {};
o[a.parentID].children = o[a.parentID].children || [];
o[a.parentID].children.push(a);
});
return o[root].children;
}
var data = { sec: "11", details: [{ id: "1", user: "Me1" }, { id: "2", uesr: "Me2" }, { id: "3", user: "Me3" }, { id: "4", user: "Me4", parentID: "2" }, { id: "5", uesr: "Me5" }, { id: "6", user: "Me6", parentID: "2" }, { id: "7", user: "Me7" }, { id: "8", user: "Me8", parentID: "7" }, { id: "9", user: "Me9", parentID: "7" }], isDisplay: "true" },
result = { sec: "11", details: getTree(data.details, undefined), isDisplay: "true" };
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

Merge objects in array by ID javascript

So I am trying to merge 2 arrays of objects by ID-s (ID and AUTOMOBIL) with this code I only push last array of objects(OPREMA). Someone have any idea how can I get all of them in the spot they should be?
So when ID in a1 is == 1 I need all of OPREMA in a2 witch AUTOMOBIL is equal to 1 to save it together it a1, but with this code it's only saving last one.
const a1 = [
{ ID: "2", TIP: "A3", VRSTA: "Limousine", $$hashKey: "object:3" },
{ ID: "1", TIP: "A5", VRSTA: "Coupe", $$hashKey: "object:7" },
];
const a2 = [
{
AUTOMOBIL: "1",
OPREMA: {
ID: "5",
NAZIV_OPREME: "Automatski",
VRSTA_OPREME: "2",
CIJENA: "15000",
OPIS: "Automatski mjenjač",
},
},
{
AUTOMOBIL: "1",
OPREMA: {
ID: "3",
NAZIV_OPREME: "Benzin",
VRSTA_OPREME: "1",
CIJENA: "7000",
OPIS: "Gorivo benzin",
},
},
{
AUTOMOBIL: "1",
OPREMA: {
ID: "19",
NAZIV_OPREME: "1.0",
VRSTA_OPREME: "5",
CIJENA: "7000",
OPIS: "potrosnja 3-6l",
},
},
{
AUTOMOBIL: "1",
OPREMA: {
ID: "11",
NAZIV_OPREME: "Sportback",
VRSTA_OPREME: "3",
CIJENA: "70000",
OPIS: "sportski izgled šasije",
},
},
{
AUTOMOBIL: "1",
OPREMA: {
ID: "8",
NAZIV_OPREME: "Quattro",
VRSTA_OPREME: "4",
CIJENA: "15000",
OPIS: "Pogon na sve kotače",
},
},
];
const a3 = a1.map(t1 => ({ ...t1, ...a2.find(t2 => t2.AUTOMOBIL === t1.ID) }));
//RESULT OF a3
console.log(a3);
In your question you never specified how exactly you want the elements of a2 to be saved in the a1 element. I'm assuming that you need them as a array under the OPREMA property. Your code was pretty close but instead of find you needed to use filter to keep all elements that match.
const a3 = a1.map(t1 => {
const matchingElements = a2.filter(t2 => t2.AUTOMOBIL === t1.ID);
return ({...t1, OPREMA: matchingElements.map(({ OPREMA }) => OPREMA) });
});

Grouping array nested value while comparing 2 objects

I am working in small react project & I am facing issue in grouping the data. Requirement is to group the id & its feature into a single row if same id is there in before & after object.
Json Data:
{
"before":{
"device": [
{
id:"1234",
price:"10,
features:[
{name:"samsung",price:"10"},
{name:"Apple",price:"20"}
]
},
{id:"2154",
price:"20,
features:[
{name:"samsung",price:"30"},
{name:"Moto",price:"40"}
]
]
},
"after":{
"device": [
{
id:"1234",
price:"50,
features:[
{name:"samsung",price:"20"},
{name:"Lenovo",price:"30"}
]
},
{id:"2158",
price:"40,
features:[
{name:"samsung",price:"30"}
]
]
}
}
Expected grouping to be shown in UI is shared in image.
I tried to get unique ids in one array and lopping through after array and comparing unique array id I am getting unique id to show but issue i am facing while grouping their related feature.
Can anyone please help me to get a best approach to handle this requirement.
Thanks
There are 3 things i'd suggest you:
1.) Please verify the data your'e posting is correct and in proper format, people won't be able to help if the data is incorrect.
2.) The UI display requirement should be simple enough.
Now, if you still want to achieve this requirement i believe the correct JSON and the merged output json will look something like below:
//Correct input data that you have:
var input = {
"before": {
"device": [
{
"id": "1234",
"price": "10",
"features": [
{
"name": "samsung",
"price": "10"
},
{
"name": "Apple",
"price": "20"
}
]
},
{
"id": "2154",
"price": "20",
"features": [
{
"name": "samsung",
"price": "30"
},
{
"name": "Moto",
"price": "40"
}
]
}
]
},
"after": {
"device": [
{
"id": "1234",
"price": "50",
"features": [
{
"name": "samsung",
"price": "20"
},
{
"name": "Lenovo",
"price": "30"
}
]
},
{
"id": "2158",
"price": "40",
"features": [
{
"name": "samsung",
"price": "30"
}
]
}
]
}
};
// Output JSON which you should need to show the desired output.
var output = {
"devices": [
{
"id": 1234,
"feature": [
{
"name": "1234",
"price": {
"before": 10,
"after": 50
}
},
{
"name": "samsung",
"price": {
"before": 10,
"after": 20
}
},
{
"name": "apple",
"price": {
"before": 10,
"after": 0
}
},
{
"name": "lenovo",
"price": {
"before": 0,
"after": 30
}
}
]
}
]
};
3.) Please try to get the desired output from input yourself as this will help you learn a lot of things in between, as suggested by some please use map, filter, forEach for your requirement.
Hope this helps. Thanks!
You could take a nested approach for grouping.
var data = { before: { device: [{ id: "1234", price: "10", features: [{ name: "samsung", price: "10" }, { name: "Apple", price: "20" }] }, { id: "2154", price: "20", features: [{ name: "samsung", price: "30" }, { name: "Moto", price: "40" }] }] }, after: { device: [{ id: "1234", price: "50", features: [{ name: "samsung", price: "20" }, { name: "Lenovo", price: "30" }] }, { id: "2158", price: "40", features: [{ name: "samsung", price: "30" }] }] } },
cols = Object.fromEntries(Object.keys(data).map(k => [k, 0])),
result = Object.values(Object.entries(data).reduce((r, [col, { device }]) => {
device.forEach(({ id, price, features }) => {
r[id] = r[id] || [{ id, ...cols }];
r[id][0][col] = price;
features.forEach(({ name, price }) => {
let temp = r[id].find(q => q.name === name);
if (!temp) r[id].push(temp = { name, ...cols });
temp[col] = price;
});
});
return r;
}, {}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use lodash library for grouping
https://lodash.com/docs/3.10.1#groupBy
Comparing 2 objects, and output equivalent values
var has = {"before":[{
name: 'Nokia',
os: 'Andriod',
features: {
camera: "200 MPixel Camera",
battery: "24 hours battery backup",
}
}],
"after":[{
name: 'Samsung',
os: 'Andriod',
features: {
camera: "200 MPixel Camera",
battery: "30 hours battery backup",
}
}]
};
function compare(Pro1, Pro2) {
var Val1 = Object.values(Pro1);
var Val2 = Object.values(Pro2);
var equivalent = [];
var keys = Object.keys(Pro1);
keys.forEach(k => {
if (Pro1.hasOwnProperty(k) && Pro2.hasOwnProperty(k)) {
if (typeof Pro1[k] === 'object') {
let recursiveResult = compare(Pro1[k], Pro2[k]);
equivalent.push(...recursiveResult);
} else if (Pro1[k] === Pro2[k]) {
equivalent.push(Pro1[k]);
}
}
});
return equivalent;
}
let equiv = compare(has["before"], has["after"]);
console.log(equiv);

How to get difference between two array of object with different property comparer?

I have these two arrays:
main:
[
{ id: "1"},
{ id: "2"},
{ id: "3"}
]
filtered:
[
{ id: "80", link_id: "1"},
{ id: "50", link_id: null},
{ id: "67", link_id: "3"}
]
I need to get the items of main which have as id those contained in filtered with the property: link_id, I tried with:
main.filter(x => filtered.includes(x.id));
the problem is that this will return null, and also this doesn't allow me to check if link_id is null
var main = [{
id: "1"
},
{
id: "2"
},
{
id: "3"
}
],
filtered = [{
id: "80",
link_id: "1"
},
{
id: "50",
link_id: null
},
{
id: "67",
link_id: "3"
}
],
result = main.filter(x =>
filtered.includes(x.id)
);
console.log(result)
Try with some() method
var main = [
{ id: "1"},
{ id: "2"},
{ id: "3"}
]
var filtered = [
{ id: "80", link_id: "1"},
{ id: "50", link_id: null},
{ id: "67", link_id: "3"}
]
console.log(main.filter(x => filtered.some(item => item.link_id === x.id) ));
you are close, basically you need to check in each item of the filtered array.
includes is more for a plain object as the documentation states.
check the snippet below, you can use findIndex, find or some to get if the element exist on the filtered array.
const main = [{
id: "1"
},
{
id: "2"
},
{
id: "3"
}
]
const filtered = [{
id: "80",
link_id: "1"
},
{
id: "50",
link_id: null
},
{
id: "67",
link_id: "3"
}
]
const resultFindIndex = main.filter(item => -1 !== filtered.findIndex(filteredItem => item.id === filteredItem.link_id))
const resultFind = main.filter(item => filtered.find(filteredItem => item.id === filteredItem.link_id))
const resultSome = main.filter(item => filtered.some(filteredItem => item.id === filteredItem.link_id))
console.log(resultFindIndex)
console.log(resultFind)
console.log(resultSome)

Filter Array based on the Filtering of Another Object having Multiple array in javascript

I have an array of objects. i want to filter array based the object has the condition.
my array is as follow :
var data = [
{
"name": "nitin",
"r_id": "1",
"t_id": "4"
},
{
"name": "test",
"r_id": "2",
"t_id": "3"
},
{
"name": "test1",
"r_id": "2",
"t_id": "4"
},
{
"name": "test3",
"r_id": "3",
"t_id": "3"
},
{
"name": "test2",
"r_id": "1",
"t_id": "1"
}]
and my object is as follows :
var obj = {
role:['1','2'],
type:['1','3']
}
where r_id is the role id and t_id is the type id
so i want the results whose role id is in 1 or 2 AND type id is in 1 or 3.
so mathematically role_id && type_id ((1||2)&&(1||3))
my output should like:
var result = [
{
'name':'test',
'r_id':2,
't_id':3,
},
{
'name':'test2',
'r_id':1,
't_id':1,
}];
var data = [
{
"name": "nitin",
"r_id": "1",
"t_id": "4"
},
{
"name": "test",
"r_id": "2",
"t_id": "3"
},
{
"name": "test1",
"r_id": "2",
"t_id": "4"
},
{
"name": "test3",
"r_id": "3",
"t_id": "3"
},
{
"name": "test2",
"r_id": "1",
"t_id": "1"
}]
var obj = {
role:['1','2'],
type:['1','3']
}
let result = data.filter(item=>{
return obj.role.indexOf(item.r_id) > -1 && obj.type.indexOf(item.t_id) > -1
})
console.log(result)
var data = [
{
"name": "nitin",
"r_id": "1",
"t_id": "4"
},
{
"name": "test",
"r_id": "2",
"t_id": "3"
},
{
"name": "test1",
"r_id": "2",
"t_id": "4"
},
{
"name": "test3",
"r_id": "3",
"t_id": "3"
},
{
"name": "test2",
"r_id": "1",
"t_id": "1"
}]
var obj = {
role:['1','2'],
type:['1','3']
}
var filterItems = data.filter(function(o){
return obj.role.indexOf(o.r_id) != -1 && obj.type.indexOf(o.t_id) != -1; });
console.log(filterItems);
You could change obj a bit, for corresponding property names in the data, you have, then use Array#filter and check with Array#every for wanted item.
var data = [{ name: "nitin", r_id: "1", t_id: "4" }, { name: "test", r_id: "2", t_id: "3" }, { name: "test1", r_id: "2", t_id: "4" }, { name: "test3", r_id: "3", t_id: "3" }, { name: "test2", r_id: "1", t_id: "1" }],
obj = { r_id: ['1', '2'], t_id: ['1', '3'] },
keys = Object.keys(obj),
result = data.filter(function (o) {
return keys.every(function (k) {
return obj[k].indexOf(o[k]) !== -1;
});
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You just need to iterate your data and see if the keys (r_id and t_id) are present in the obj (in the respective arrays). For this you can use Array.filter
var data = [{"name":"nitin","r_id":"1","t_id":"4"},{"name":"test","r_id":"2","t_id":"3"},{"name":"test1","r_id":"2","t_id":"4"},{"name":"test3","r_id":"3","t_id":"3"},{"name":"test2","r_id":"1","t_id":"1"}]
var obj = {
role:['1','2'],
type:['1','3']
}
var result = data.filter(function(element){
return obj.role.indexOf(element.r_id) !== -1 && // element has valid role
obj.type.indexOf(element.t_id) !== -1 // element has valid type
})
console.log(result)

How to create tree view in js

I have a dummy data like this
i need to create a tree like this
CEO
A
A1
A2
My dummy look like this
let d = [
{
"name": "CEO",
"parent": null,
"id": "5847e80312896b2fa49ce428"
},
{
"name": "A",
"parent": "5847e80312896b2fa49ce428",
"id": "5847f58289046550aa05a49d"
},
{
"name": "A1",
"parent": "5847f58289046550aa05a49d",
"id": "584804b073697edd3d372529"
},
{
"name": "A2",
"parent": "5847e80312896b2fa49ce428",
"id": "584804b073697edd3d372539"
}
];
I have tried somthing like this
var newObj = {tree:d.filter(d=>!d.parent)};
var tree = newObj.tree;
for(let k in tree){
for(let i = 0 ; i < tree.length ; i++){
newObj.tree[i]['child']=this.returnChildNode(tree[i].id,d);
}
}
console.log(newObj);
private returnChildNode(parentId ,arr){
if(arr.filter(d=>d.parent===parentId).length < 1) return null ;
else return arr.filter(d=>d.parent===parentId);
}
Output getting is
{
"tree": [
{
"name": "CEO",
"parent": null,
"id": "5847e80312896b2fa49ce428",
"child": [
{
"name": "A",
"parent": "5847e80312896b2fa49ce428",
"id": "5847f58289046550aa05a49d"
},
{
"name": "A2",
"parent": "5847e80312896b2fa49ce428",
"id": "584804b073697edd3d372539"
}
]
}
]
}
How to complete it by recursion for deep going in generic way
Here's a recursive option using reduce
let d = [{
"name": "CEO",
"parent": null,
"id": "5847e80312896b2fa49ce428"
}, {
"name": "A",
"parent": "5847e80312896b2fa49ce428",
"id": "5847f58289046550aa05a49d"
}, {
"name": "A1",
"parent": "5847f58289046550aa05a49d",
"id": "584804b073697edd3d372529"
}, {
"name": "A2",
"parent": "5847e80312896b2fa49ce428",
"id": "584804b073697edd3d372539"
}]
const rec = (parent, arr) => {
const ref = parent ? parent.id : null
const children = arr.reduce((ac, x) => {
if (x.parent === ref)
ac.push(rec(x, arr))
return ac
}, [])
if (parent)
parent.children = children
return (
parent ?
parent :
children[0]
)
}
const res = rec(null, d)
console.log(res)
You can try this :
var data = [
{
name: "CEO",
parent: null,
id: "0"
},
{
name: "A",
parent: "0",
id: "1"
},
{
name: "A1",
parent: "1",
id: "2"
},
{
name: "A2",
parent: "1",
id: "3"
},
{
name: "A3",
parent: "1",
id: "4"
},
{
name: "b",
parent: "0",
id: "5"
},
{
name: "A1",
parent: "5",
id: "6"
},
{
name: "A2",
parent: "5",
id: "7"
},
{
name: "A3",
parent: "5",
id: "8"
},
];
// data is an array in the above format
function toTree(data) {
var childrenById = {}; // of the form id: [child-ids]
var nodes = {}; // of the form id: {name: children: }
var i, row;
// first pass: build child arrays and initial node array
for (i=0; i<data.length; i++) {
row = data[i];
nodes[row.id] = {name: row.name, children: []};
if (row.parent == null) {
// assume -1 is used to mark the root's "parent"
root = row.id;
} else if (childrenById[row.parent] === undefined) {
childrenById[row.parent] = [row.id];
} else {
childrenById[row.parent].push(row.id);
}
}
// second pass: build tree, using the awesome power of recursion!
function expand(id) {
if (childrenById[id] !== undefined) {
for (var i=0; i < childrenById[id].length; i ++) {
var childId = childrenById[id][i];
nodes[id].children.push(expand(childId));
}
}
return nodes[id];
}
return expand(root);
}
console.log(JSON.stringify(toTree(data)));

Categories