I am planning to filter an array into 2 separate arrays based on flag in one of the inner arrays but having trouble. Please help me with my code.
How do we get 2 separate arrays out of apiData to have objects filtered in types array based on flag value
var apiData = [{
"id": 1,
"types": [{
"id": "1.1",
"flag": true,
},
"id": "1.2",
"flag": false
}]
},
"id": 2,
"types": [{
"id": "2.1",
"flag": true,
}]
}
]
My Result should be like this for filteredTrueArray [{
"id": 1,
"types": [{
"id": "1.1",
"flag": true,
}]
},
"id": 2,
"types": [{
"id": "2.1",
"flag": true,
}]
}
]
I wanted $scope.filteredTrueArray to have types array with flag=true value objects and another array to have types array with only flag=false objects. Below is my code
$scope.filteredTrueArray = apiData.filter(function(item) {
var isTrueFound = item.types.some(function (el) {
return el.flag == true;
});
if(isTrueFound){
for(var i=0;i<item.types.length>0;i++)
{
if(item.types[i].flag == true){
$scope.filteredTrueArray.push(item.types[i]);
}
}
}
});
I've written a simple filter function. Please take a look!
var apiData = [{
"id": 1,
"types": [{
"id": "1.1",
"flag": true,
}, {
"id": "1.2",
"flag": false
}]
}, {
"id": 2,
"types": [{
"id": "2.1",
"flag": true,
}]
}];
function filterByTypeFlag(records, flagValue) {
var filtered = [];
records.forEach(function (record) {
var matchedTypes = [];
record.types.forEach(function (type) {
if (type.flag === flagValue) {
matchedTypes.push(type);
}
});
if (matchedTypes.length) {
filtered.push({
"id": record.id,
"types": matchedTypes
});
}
});
return filtered;
}
filterByTypeFlag(apiData, true);
filterByTypeFlag(apiData, false);
Here is a sample code that creates an object with a boolean value and creates 2 arrays of objects bases off their boolean value. Sorry if I misunderstood what you were looking for.
var objArray = [];
class testObj {
constructor(Oname, test1) {
this.name = Oname;
this.isABoolean = test1;
objArray.push(this);
}
}
var test1 = new testObj("test1", false);
var test2 = new testObj("test2", true);
var test3 = new testObj("test3", false);
var test4 = new testObj("test4", true);
var test5 = new testObj("test5", false);
var objArray = [test1, test2, test3, test4, test5];
var trueArray = [];
var falseArray = [];
function createArrays() {
for (var i = 0; i < objArray.length; i++) {
if (objArray[i].isABoolean === true) {
trueArray.push(objArray[i]);
//console.log(trueArray[i].name);
} else if (objArray[i].isABoolean === false) {
falseArray.push(objArray[i]);
}
}
}
createArrays();
for (var j = 0; j < trueArray.length; j++) {
console.log("True value: " + trueArray[j].name);
}
for (var k = 0; k < falseArray.length; k++) {
console.log("False value " + falseArray[k].name);
}
EDIT: I cleaned it up to automatically add the objects to an array upon creation.
One solution is to use map() with a filter() for get the new types array.
var apiData = [
{
"id": 1,
"types": [
{"id": "1.1", "flag": true},
{"id": "1.2", "flag": false}
]
},
{
"id": 2,
"types": [
{"id": "2.1", "flag": true}
]
}
];
let filteredTrueArray = apiData.map(
({id, types}) => ({id, types: types.filter(x => x.flag)})
)
.filter(({types}) => types.length);
let filteredFalseArray = apiData.map(
({id, types}) => ({id, types: types.filter(x => !x.flag)})
)
.filter(({types}) => types.length);
console.log("FilteredTrueArray:", filteredTrueArray);
console.log("FilteredFalseArray:", filteredFalseArray);
I would like to merge 2 objects with the same properties into an Array.
Take this for an example:
object1 = {"id":1,
"name":name1,
"children":[{"id":2,"name":name2}]
};
object2 = {"id":3,
"name":name3,
"children":[{"id":4,"name":name4}]
};
object3 = {"id":1,
"name":name1,
"children":[{"id":6,"name":name6}]
};
var result = Object.assign(result,object1,object2,object3);
Expected result:
JSON.stringify([result]) =[
{"id":1,
"name":name1,
"children":[{"id":2,"name":name2},
{"id":6,"name":name6}]
},
{"id":3,
"name":name3,
"children":[{"id":4,"name":name4}]
}
]
Actual result:
JSON.stringify([result]) = [
{"id":3,
"name":name3,
"children":[{"id":4,"name":name4}]
}
]
Seems like Object.assign() isn't the way to go... as it will overwrite, I do not want it to overwrite, I want them to merge instead. Is there a right way to do this?
As so often, Array.prototype.reduce provides a good base for an approach like e.g. this one ...
var obj1 = {
"id": 1,
"name": "name1",
"children": [{ "id": 2, "name": "name2" }]
};
var obj2 = {
"id": 3,
"name": "name3",
"children": [{ "id": 4, "name": "name4" }]
};
var obj3 = {
"id": 1,
"name": "name1",
"children": [{ "id": 6, "name": "name6" }]
};
// Expected result: [{
// "id": 1,
// "name": name1,
// "children": [
// { "id": 2, "name": "name2" },
// { "id": 6, "name": "name6" }
// ]
// }, {
// "id": 3,
// "name": "name3",
// "children": [{"id": 4, "name": "name4" }]
// }]
function mergeEquallyLabeledTypes(collector, type) {
var key = (type.name + '#' + type.id); // identity key.
var store = collector.store;
var storedType = store[key];
if (storedType) { // merge `children` of identically named types.
storedType.children = storedType.children.concat(type.children);
} else {
store[key] = type;
collector.list.push(type);
}
return collector;
}
var result = [obj1, obj2, obj3].reduce(mergeEquallyLabeledTypes, {
store: {},
list: []
}).list;
console.log('result : ', result);
.as-console-wrapper { max-height: 100%!important; top: 0; }
Edit Note
After having been informed about changed requirements, that need to deal with a nested pattern, I will change my first provided approach into a generic solution. It will be not that difficult since there is a generically repeated pattern within the data structure. Thus I just need to make the already existing reducer function self recursive. A recursion step will be triggered after having finished a complete reducing cycle on any provided list ...
var obj1 = {
"id": 1,
"name": "name1",
"children": [{ "id": 2, "name": "name2", "children": [{ "id": 8, "name": "name8" }] }]
};
var obj2 = {
"id": 3,
"name": "name3",
"children": [{ "id": 4, "name": "name4", "children": [{ "id": 9, "name": "name9" }] }]
};
var obj3 = {
"id": 1,
"name": "name1",
"children": [{ "id": 6, "name": "name6", "children": [{ "id": 10, "name": "name10" }] }]
};
var obj4 = {
"id": 3,
"name": "name3",
"children": [{ "id": 4, "name": "name4", "children": [{ "id": 11, "name": "name11" }] }]
};
function mergeEquallyLabeledTypesRecursively(collector, type, idx, list) {
var key = (type.name + '#' + type.id); // identity key.
var store = collector.store;
var storedType = store[key];
if (storedType) { // merge `children` of identically named types.
storedType.children = storedType.children.concat(type.children);
} else {
store[key] = type;
collector.list.push(type);
}
// take repetitive data patterns into account ...
if (idx >= (list.length - 1)) {
collector.list.forEach(function (type) {
// ... behave recursive, when appropriate.
if (type.children) {
type.children = type.children.reduce(mergeEquallyLabeledTypesRecursively, {
store: {},
list: []
}).list;
}
});
}
return collector;
}
var result = [obj1, obj2, obj3, obj4].reduce(mergeEquallyLabeledTypesRecursively, {
store: {},
list: []
}).list;
console.log('result : ', result);
.as-console-wrapper { max-height: 100%!important; top: 0; }
This might be what your after, please note it's not recursive now recursive. But your example data doesn't appear to be anyway.
const object1 = {"id":1,
"name":"name1",
"children":[{"id":2,"name":"name2"}]
};
const object2 = {"id":3,
"name":"name3",
"children":[{"id":4,"name":"name4"}]
};
const object3 = {"id":1,
"name":"name1",
"children":[
{"id":6,"name":"name6"},
{"id":7,"name":"name7"},
{"id":6,"name":"name6"}
]
};
function merge(arr) {
const idLinks = {};
const ret = [];
arr.forEach((r) => {
if (!idLinks[r.id]) idLinks[r.id] = [];
idLinks[r.id].push(r);
});
Object.keys(idLinks).forEach((k) => {
const nn = idLinks[k];
const n = nn[0];
for (let l = 1; l < nn.length; l ++) {
if (nn[l].children) {
if (!n.children) n.children = [];
n.children = n.children.concat(nn[l].children);
}
}
if (n.children && n.children.length) n.children = merge(n.children);
ret.push(n);
});
return ret;
}
var result = merge([object1,object2,object3]);
console.log(result);
/* There are two cases :
a) No duplicate children
b) Duplicate children either in (same object || different object|| both)
*/
/* =============== */
/* Case a) */
const util = require('util');
var object1 = {
"id": 1,
"name": "name1",
"children": [{ "id": 2, "name": "name2" }]
};
var object2 = {
"id": 3,
"name": "name3",
"children": [{ "id": 4, "name": "name4" }]
};
var object3 = {
"id": 1,
"name":"name1",
"children":[{"id":6,"name":"name6"}]
};
var arr = [object1,object2,object3];
var uniqueIds = [];
var filteredArray = [];
var uniqueId='';
arr.map((item,i,array)=>{
uniqueId =uniqueIds.indexOf(item.id);
uniqueId = uniqueId+1;
uniqueIds = [...uniqueIds,item.id];
if(!uniqueId){
filteredArray[i] = item;
}
if(uniqueId){
filteredArray[uniqueId-1]['children'] = [...(array[uniqueId-1].children),...(item.children)];
}
});
console.log(util.inspect(filteredArray,false,null));
/* ============================================
Case b)
Dealing with the worst case of having duplicate children in both same
and different objects
*/
object1 = {"id":1,
"name":'name1',
"children":[{"id":2,"name":'name2'},
{"id":2,"name":'name2'}]
};
object2 = {"id":3,
"name":'name3',
"children":[{"id":4,"name":'name4'}]
};
object3 = {"id":1,
"name":'name1',
"children":[{"id":6,"name":'name6'},
{"id":7,"name":'name7'},
{"id":2,"name":'name2'}]
};
arr = [object1,object2,object3];
uniqueIds = [];
uniqueId = '';
arr.map((item,i,array)=>{
uniqueId =uniqueIds.indexOf(item.id);
uniqueId = uniqueId+1;
uniqueIds = [...uniqueIds,item.id];
if(!uniqueId){
filteredArray[i] = item;
}
if(uniqueId){
filteredArray[uniqueId-1]['children'] = [...(array[uniqueId-1].children),...(item.children)];
}
/*Removing duplicate children entries*/
filteredArray[uniqueIds.indexOf(item.id)]['children'] = filteredArray[uniqueIds.indexOf(item.id)]['children']
.filter((elem, index, self) => self.findIndex((t) => {return t.id === elem.id}) === index)
})
console.log(util.inspect(filteredArray,false,null));
In functional programming way with es6 standards. I am assuming children array also contains duplicates. I enclosed the code in closures.
See the following link why I used util to print all the object in node console.log()
How can I get the full object in Node.js's console.log(), rather than '[Object]'?
(function() {
'use strict';
const util = require('util');
/** string constants */
const ID = 'id';
const CHILDREN = 'children';
/* Objects to modify */
const object1 = {
"id": 1,
"name": "name1",
"children": [
{ "id": 2, "name": "name2" },
{ "id": 5, "name": "name5" },
{ "id": 7, "name": "name7" }
]
};
const object2 = {
"id": 3,
"name": "name3",
"children": [
{ "id": 4, "name": "name4" }
]
};
const object3 = {
"id": 1,
"name": "name1",
"children": [
{ "id": 5, "name": "name5" },
{ "id": 6, "name": "name6" }
]
};
/**
* Concates the arrays
* #param { array } - a
* #param { array } - b
*/
const merge = (a, b) => {
return a.concat(b);
};
/**
* Removes Duplicates from the given array based on ID
* #param { array } - array to remove duplicates
* #return { array } - array without duplicates
*/
const removeDuplicates = (arr) => {
return arr.filter((obj, pos, arr) => {
return arr.map((m) => {
return m[ID];
}).indexOf(obj[ID]) === pos;
});
}
/**
* Groups items in array with particular key
* Currying technique
* #param { prop } - key to group
* #return { () => {} } - Method which in turn takes array as argument
*/
const groupBy = (prop) => (array) => {
return array.reduce((groups, item) => {
const val = item[prop];
groups[val] = groups[val] || [];
groups[val].push(item);
return groups;
}, {});
}
/**
* Object containing grouped-items by particuar key
*/
const grouped = groupBy(ID)([object1, object2, object3]);
/**
* Removing the duplicates of children
* Remember map also mutates the array of objects key's value
* but not data type
*/
Object.keys(grouped).map((key, position) => {
grouped[key].reduce((a, b) => {
a[CHILDREN] = removeDuplicates(a[CHILDREN].concat(b[CHILDREN]));
});
});
/**
* Desired final output
*/
const final = Object.keys(grouped)
.map((key) => removeDuplicates(grouped[key]))
.reduce(merge, []);
console.log(util.inspect(final, false, null))})();
const object1 = {
"id":1,
"name":"name1",
"children":[{"id":2,"name":"name2"}]
};
const object2 = {
"id":3,
"name":"name3",
"children":[{"id":4,"name":"name4"}]
};
const object3 = {
"id":1,
"name":"name1",
"children":[{"id":6,"name":"name6"}]
};
var array = [object1,object2,object3];
var array2 = [object1,object2,object3];
function uniquearray(obj){
var result =[];
for(var i=0;i<array.length;i++){
if(obj.id == array[i].id){
result.push(array[i])
array.splice(i,1)
}
}
return result;
}
var arrayofuniarrays = []
for(var i=0;i<array2.length;i++){
arrayofuniarrays.push(uniquearray(array2[i]))
}
for(var i=0;i<arrayofuniarrays.length;i++){
for(var j=1;j<arrayofuniarrays[i].length; j++){
arrayofuniarrays[i][0].children.push(arrayofuniarrays[i][j].children)
arrayofuniarrays[i].splice(j,1)
}
}
var resul = arrayofuniarrays.reduce(function(a, b){return a.concat(b)},[])
console.log(resul)
Here is a sketch example of how to do this. It leverages a mapped type using your id as a key to ensure each item only appears once. It adds all of the children to an array based on the id.
If you needed to enforce the same behaviour on the children, you could use the same technique.
I have split this into multiple iterations to show you the individual parts in play.
Usually, it is more efficient to avoid creating objects that need to be zipped back up if you can.
const object1 = {
"id": 1,
"name": "name1",
"children": [{ "id": 2, "name": "name2" }]
};
const object2 = {
"id": 3,
"name": "name3",
"children": [{ "id": 4, "name": "name4" }]
};
const object3 = {
"id": 1,
"name":"name1",
"children":[{"id":6,"name":"name6"}]
};
const all = [object1, object2, object3];
// Use a map like a dictionary to enforce unique keys
const mapped = {};
for (let obj of all) {
if (!mapped[obj.id]) {
mapped[obj.id] = obj;
continue;
}
mapped[obj.id].children.push(obj.children);
}
console.log('Mapped ==> '+JSON.stringify(mapped));
// If you want to convert the mapped type to an array
const result = [];
for (let key in mapped) {
result.push(mapped[key]);
}
console.log('Array ==> '+JSON.stringify(result));
Building on #Peter Seliger's answer here, I derived with the following method to merge arrays with deeply nested children.
Given the following objects:
var obj1 = {
"id": 1,
"name": "name1",
"children": [{ "id": 2, "name": "name2", children:[{ "id":8, "name": "name8" }] }]
};
var obj2 = {
"id": 3,
"name": "name3",
"children": [{ "id": 4, "name": "name4", children:[{ "id":9, "name": "name9" }] }]
};
var obj3 = {
"id": 1,
"name": "name1",
"children": [{ "id": 6, "name": "name6", children:[{ "id":10, "name": "name10" }] }]
};
var obj4 = {
"id": 3,
"name": "name3",
"children": [{ "id": 4, "name": "name4", children:[{ "id":11, "name": "name11" }] }]
};
First we merge the parents
function mergeEquallyLabeledTypes(collector, type) {
var key = (type.name + '#' + type.id); // identity key.
var store = collector.store;
var storedType = store[key];
if (storedType) { // merge `children` of identically named types.
if(storedType.children)
storedType.children = storedType.children.concat(type.children);
} else {
store[key] = type;
collector.list.push(type);
}
return collector;
}
var result = [obj1, obj2, obj3, obj4].reduce(mergeEquallyLabeledTypes, {
store: {},
list: []
}).list;
Then we merge the children and subchildren if any.
for(let i=0; i<result.length; i++){
var children = result[i].children;
if(children){
var reducedChildren = children.reduce(mergeEquallyLabeledTypes, {store: {}, list: []}).list;
for(let j=0; j<reducedChildren.length; j++){
var subchildren = reducedChildren[j].children;
if(subchildren){
var reducedSubchildren = subchildren.reduce(mergeEquallyLabeledTypes, {store: {}, list: []}).list;
reducedChildren[j].children = reducedSubchildren;
}
}
result[i].children = reducedChildren;
}
}
Finally the result will be what I'll parse into my website.
console.log('result : ', result);
I am able to get the expected result.
// result: [{
// "id": 1,
// "name": name1,
// "children": [
// { "id": 2, "name": "name2", children:[{ "id":8, "name": "name8" }] },
// { "id": 6, "name": "name6", children:[{ "id":10, "name": "name10" }] }
// ]
// }, {
// "id": 3,
// "name": "name3",
// "children": [{"id": 4, "name": "name4", children:[
// { "id":9, "name": "name9" },
// { "id":11, "name": "name11" }
// ]
// }
// ]
// }]
However, this might not be too efficient as I'll need to keep adding on to the merging of children/subchildren method if my tree get nested with more levels. (e.g. subsubchildren, subsubsubchildren and so on...)
Is there any more efficient way to do this?
const object1 = {
id:1,
name:'a',
}
const object2 = {
id:3,
name:'b',
}
const object3 = {
id:1,
name:'c',
}
const originArr = [object1, object2, object3]
const idArr = [object1.id, object2.id, object3.id]
const newIdArr = []
for (let id of idArr) {
if (newIdArr.indexOf(id)) newIdArr.push(id)
}
const result = newIdArr.map(id => {
let names = []
for (obj of originArr) {
if (id === obj.id) names.push(obj.name)
}
return { id, names }
})
console.log(result)
This function returns diff between two objects , i need to modify it to return common objects. Any help is appreciated.
Array sample:
var array1 = [{
"Name": "Single",
"URL": "xxx",
"ID": 123
}, {
"Name": "Double",
"URL": "yyy",
"ID": 888
}, {
"Name": "Triple",
"URL": "zzz",
"ID": 567
}];
var arrar2 = [{
"Name": "Single",
"URL": "xxx",
"ID": 123
}, {
"Name": "Double",
"URL": "yyy",
"ID": 888
}, {
"Name": "index",
"URL": "zzz",
"ID": 567
}];
// expected result
var resultArray = [{
"Name": "Single",
"URL": "xxx",
"ID": 123
}, {
"Name": "Double",
"URL": "yyy",
"ID": 888
},
}];
Current code:
function objDiff(array1, array2) {
var resultArray = []
array2.forEach(function(destObj) {
var check = array1.some(function(origObj) {
if (origObj.name == destObj.name) return true
})
if (!check) {
destObj.desc = 'missing in source'
resultArray.push(destObj)
}
})
array1.forEach(function(origObj) {
var check = array2.some(function(destObj) {
if (origObj.name == destObj.name) return true
})
if (!check) {
origObj.desc = 'missing in destination'
resultArray.push(origObj)
}
})
return resultArray
}
If all you want is to look for things that are the same in both arrays, you only need to loop over one of them. Something along these lines should work:
function objSame(array1, array2) {
var resultArray = []
array2.forEach(function(destObj) {
var check = array1.some(function(origObj) {
if(origObj.name == destObj.name) return true
})
if(check) {
destObj.desc = 'Same in both'
resultArray.push(destObj)
}
})
return resultArray
}
To find array elements that have a common Name property value, you could use a Map to avoid O(n²) time complexity. That map would have the objects from the first array keyed by their name. Pass it as the this object to a filter on the second array:
function objCommon(array1, array2) {
return array2.filter(function (obj) {
return this.has(obj.Name);
}, new Map(array1.map(obj => [obj.Name, obj])));
}
var array1= [
{ "Name": "Single", "URL": "xxx", "ID": 123 },
{ "Name": "Double", "URL": "yyy", "ID": 888},
{ "Name": "Triple", "URL": "zzz", "ID": 567 }];
var array2= [
{ "Name": "Single", "URL": "xxx", "ID": 123 },
{ "Name": "Double", "URL": "yyy", "ID": 888 },
{ "Name": "index", "URL": "zzz", "ID": 567 }];
var result = objCommon(array1, array2);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
That's not your code, but the following function will return all matches by exploring both arrays with two forEach() loops. Algorithm complexity is given by array1.length * array2.length. Don't use for large arrays! But it's the easiest way to think of it. Indeed the first think that comes to my mind is checking every element of array2 for every element of array1 and compare them.
var array1 = ['DETE', 'Ivany', 'James', 'Don', 'Crakcer']
var array2 = ['Jamies', 'Ivanyy', 'DETE', 'Don']
function objMatch(array1,array2) {
var matches = [];
array1.forEach(function(element1) {
array2.forEach(function(element2) {
if(element1 == element2) {
matches.push(element1);
}
});
});
return matches;
}
console.log(objMatch(array1, array2));
// will return ['DETE', 'Don']
Another way to do with only one loop is to use sort(), credit to jeremy
var array1 = ["cat", "sum","fun", "run", "gut"];
var array2 = ["bat", "cat","dog","sun", "hut", "gut"];
var arrayMatch = function(array1, array2) {
var matches = [];
array1.sort();
array2.sort();
for (var i = 0; i < array1.length; i += 1) {
if (array2.indexOf(array1[i]) > -1) {
matches.push(array1[i]);
}
}
return matches;
}
console.log(arrayMatch(array1,array2))
And yet another way to do it is by using Array.prototype.filter, credit to Paul S.
var array1 = ['DETE', 'Ivany', 'James', 'Don', 'Crakcer']
var array2 = ['Jamies', 'Ivanyy', 'DETE', 'Don']
function arrayMatch(array1, array2) {
var t;
if (array1.length > array2.length) t = array2, array2 = array1, array1 = t;
return array1.filter(function (e) {
return array2.indexOf(e) > -1;
});
}
console.log(arrayMatch(array1, array2));
I have 2 separate arrays which I need to merge into a third one so I can get all the data required.
Basically the 1st array has an id, and name and in order to get the address I need to search inside the 2nd array and match the id's so I can have all the data from the person.
Here is the data and code:
//Array 1
var myPeopleArray = [{"people":[{"id":"123","name":"name 1"},{"id":"456","name":"name 2"}]}];
//Array 2
var myPersonArray = [{"person":[{"id":"123","address":"address 1"},{"id":"456","address":"address 2"}]}];
var arrayLength = myPeopleArray[0].people.length;
for (var i = 0; i < arrayLength; i++) {
console.log("id: " + myPeopleArray[0].people[i].id);
}
//Wanted Result:
[{"people":[
{
"id":"123",
"name":"name 1",
"address":"address 1"
},
{
"id":"456",
"name":"name 2",
"address":"address 2"
}
]
}]
How can I do this?
var myPeopleArray = [{"people":[{"id":"123","name":"name 1"}, {"id":"456","name":"name 2"}]}];
var myPersonArray = [{"person":[{"id":"123","address":"address 1"}, {"id":"456","address":"address 2"}]}];
for(var i=0;i<myPeopleArray[0].people.length;i++)
{
myPeopleArray[0].people[i].address = myPersonArray[0].person[i].address;
}
document.write(JSON.stringify(myPeopleArray));
You could iterate both arrays and build new object with the joined properties.
var myPeopleArray = [{ "people": [{ "id": "123", "name": "name 1" }, { "id": "456", "name": "name 2" }] }],
myPersonArray = [{ "person": [{ "id": "123", "address": "address 1" }, { "id": "456", "address": "address 2" }] }],
hash = Object.create(null),
joined = [],
joinById = function (o) {
if (!(o.id in hash)) {
hash[o.id] = {};
joined.push(hash[o.id]);
}
Object.keys(o).forEach(function (k) {
hash[o.id][k] = o[k];
});
};
myPeopleArray[0].people.forEach(joinById);
myPersonArray[0].person.forEach(joinById);
console.log(joined);
This question already has answers here:
How to get the difference between two arrays in JavaScript?
(84 answers)
Closed 7 years ago.
Using jQuery I would like to compare 2 objects:
sourceArray:
var origArray = [{
"Name": "Single",
"URL": "xxx",
"ID": 123
},
{
"Name": "Double",
"URL": "yyy",
"ID": 345
},
{
"Name": "Family",
"URL": "zzz",
"ID": 567
}];
destination array
var destArray = [{
"Name": "Single",
"URL": "xxx",
"ID": 123
},
{
"Name": "Double",
"URL": "yyy",
"ID": 888
},
{
"Name": "Family",
"URL": "zzz",
"ID": 567
}];
What I would like to do, is compare the target object with the source object based on the ID and find the mis-matched entries with a description on the resultant object. So the result will look like this:
var resultArray = [{
"Name": "Double",
"URL": "yyy",
"ID": 888,
"desc": "missing in source"
},
{
"Name": "Double",
"URL": "yyy",
"ID": 345,
"desc": "missing in destination"
}];
Any quick help is really appreciated.
This isn't a good use of jQuery, but here is some vanilla javascript that does what you want.
function objDiff(array1, array2) {
var resultArray = []
array2.forEach(function(destObj) {
var check = array1.some(function(origObj) {
if(origObj.ID == destObj.ID) return true
})
if(!check) {
destObj.desc = 'missing in source'
resultArray.push(destObj)
}
})
array1.forEach(function(origObj) {
var check = array2.some(function(destObj) {
if(origObj.ID == destObj.ID) return true
})
if(!check) {
origObj.desc = 'missing in destination'
resultArray.push(origObj)
}
})
return resultArray
}
https://jsfiddle.net/9gaxsLbz/1/
If you are wanting to dedupe your array, this will work:
var merged = origArray.concat(destArray);
var unique = merged.filter(function(item) {
return ~this.indexOf(item.ID) ? false : this.push(item.ID);
}, []);
Fiddle: https://jsfiddle.net/Ljzor9c6/
If you are only wanting items that were duped, you can easily invert the condition:
var merged = origArray.concat(destArray);
var dupes = merged.filter(function(item) {
return ~this.indexOf(item.ID) ? true : !this.push(item.ID);
}, []);
You can loop through the items in the first array and put the ID's in a map, then loop through the items in the second array and remove the matching ID's and add the missing.
Then just loop through the map to create the objects in the resulting array:
var origArray = [{
"Name": "Single",
"URL": "xxx",
"ID": 123
},
{
"Name": "Double",
"URL": "yyy",
"ID": 345
},
{
"Name": "Family",
"URL": "zzz",
"ID": 567
}];
var destArray = [{
"Name": "Single",
"URL": "xxx",
"ID": 123
},
{
"Name": "Double",
"URL": "yyy",
"ID": 888
},
{
"Name": "Family",
"URL": "zzz",
"ID": 567
}];
var map = {};
for (var i = 0; i < origArray.length; i++) {
map[origArray[i].ID] = 'source';
}
for (var i = 0; i < destArray.length; i++) {
var id = destArray[i].ID;
if (id in map) {
delete map[id];
} else {
map[id] = 'destination';
}
}
var resultArray = [];
for (key in map) {
var arr = map[key] == 'source' ? origArray : destArray;
for (var i = 0; arr[i].ID != key; i++) ;
resultArray.push({
Name: arr[i].Name,
URL: arr[i].URL,
ID: arr[i].ID,
desc: 'missing in ' + map[key]
});
}
// show result in StackOverflow snippet
document.write(JSON.stringify(resultArray));
var result = [];
for(var i = 0; i < oa.length; i++) {
var idx = mIndexOf(oa[i].ID);
if(idx > -1) {
oa.splice(i, 1);
da.splice(idx, 1);
}
}
for(var i = 0; i < oa.length; i++) {
var ln = result.length;
result[ln] = oa[i];
result[ln].desc = "missing in destination";
}
for(var i = 0; i < da.length; i++) {
var ln = result.length;
result[ln] = da[i];
result[ln].desc = "missing in origin";
}
function mIndexOf(id) {
for(var i = 0; i < oa.length; i++)
if(oa[i].ID == id)
return i;
return -1;
}
console.log(result);
0: Object
ID: 345
Name: "Double"
URL: "yyy"
desc: "missing in destination"
1: Object
ID: 888
Name: "Double"
URL: "yyy"
desc: "missing in origin"
jsfiddle DEMO
For things like this, you should use lodash. With lodash you can just do this:
var resultArray = _.defaults(destArray, origArray);