I have following array of objects.
[{"rId":24,"gId":40,"sId":20,"disabled":false},
{"rId":24,"gId":40,"sId":19,"disabled":false},
{"rId":24,"gId":40,"sId":50,"disabled":false},
{"rId":24,"gId":40,"sId":20,"disabled":true},
{"rId":24,"gId":40,"sId":19,"disabled":true},
{"rId":24,"gId":40,"sId":50,"disabled":true},
{"rId":24,"gId":39,"sId":18,"disabled":false}]
In which some records are antithesis ex. 1st element and 4th which has same rId, gId, and sId but disabled flag is opposite. I want to eliminate all such records.
My expected array is {"rId":24,"gId":39,"sId":18,"disabled":false} (eliminate all antithesis records)
I tried following code but it is giving me wrong output.
arrOfObj=[{"rId":24,"gId":40,"sId":20,"disabled":false},
{"rId":24,"gId":40,"sId":19,"disabled":false},
{"rId":24,"gId":40,"sId":50,"disabled":false},
{"rId":24,"gId":40,"sId":20,"disabled":true},
{"rId":24,"gId":40,"sId":19,"disabled":true},
{"rId":24,"gId":40,"sId":50,"disabled":true},
{"rId":24,"gId":39,"sId":18,"disabled":false}]
$.each(arrOfObj,function (index1,firstObj) {
$.each(arrOfObj,function (index2,secondObj) {
if(index1>= index2){
return true;
}
var areObjAntithesis=firstObj.rId===secondObj.rId && firstObj.gId===secondObj.gId
&& firstObj.sId===secondObj.sId && firstObj.disabled!==secondObj.disabled;
if(areObjAntithesis){
arrOfObj.splice(index1,1);
arrOfObj.splice(index2,1)
return false;
}
})
})
Is there any elegant way to achieve expected output ?
5 Answers 5
You could do this with map() and filter()
var data = [{"rId":24,"gId":40,"sId":20,"disabled":false},
{"rId":24,"gId":40,"sId":19,"disabled":false},
{"rId":24,"gId":40,"sId":50,"disabled":false},
{"rId":24,"gId":40,"sId":20,"disabled":true},
{"rId":24,"gId":40,"sId":19,"disabled":true},
{"rId":24,"gId":40,"sId":50,"disabled":true},
{"rId":24,"gId":39,"sId":18,"disabled":false}]
var ar = data.map(function(e) {
return e.rId + '|' + e.gId + '|' + e.sId;
});
var result = data.filter(function(e) {
var key = e.rId + '|' + e.gId + '|' + e.sId;
return ar.indexOf(key) == ar.lastIndexOf(key);
});
console.log(result)
Comments
Use http://underscorejs.org/#where and do like that:
var newArrOfObj=_.where(arrOfObj, {disabled:true});
Comments
You can use multiple array.filter and check count and only return elements which have more than 1 value and if values are same or have only one value
var data = [{"rId":24,"gId":40,"sId":20,"disabled":false},
{"rId":24,"gId":40,"sId":19,"disabled":false},
{"rId":24,"gId":40,"sId":50,"disabled":false},
{"rId":24,"gId":40,"sId":20,"disabled":true},
{"rId":24,"gId":40,"sId":19,"disabled":true},
{"rId":24,"gId":40,"sId":50,"disabled":true},
{"rId":24,"gId":39,"sId":18,"disabled":false}]
var result = data.filter(function(outer){
var disablesValues = []
var _r = data.filter(function(inner){
if(inner.gId === outer.gId && inner.sId === outer.sId){
if(disablesValues.indexOf(inner.disabled) < 0)
disablesValues.push(inner.disabled);
return true;
}
});
return _r.length === 1 || disablesValues.length === 1
});
console.log(result)
Comments
Here is functional programming style ES6 solution, which will deal with more repetitions as well, counting how the number of disabled and enabled objects balance annihilate each other:
function eliminateOpposites(arr) {
return [...arr
.map( o => ({ o, k: JSON.stringify({ rId:o.rId, gId:o.gId, sId:o.sId }) }) )
.reduce( (acc, o) => acc.set(o.k, (acc.get(o.k) || 0)+ (+o.o.disabled || -1)),
new Map() )]
.filter( ([k, balance]) => balance )
.map( ([k, balance]) => Object.assign(JSON.parse(k), {disabled: balance>0}));
}
// Sample data
var arrOfObj=[
{"rId":24,"gId":40,"sId":20,"disabled":false},
{"rId":24,"gId":40,"sId":19,"disabled":false},
{"rId":24,"gId":40,"sId":50,"disabled":false},
{"rId":24,"gId":40,"sId":20,"disabled":true},
{"rId":24,"gId":40,"sId":19,"disabled":true},
{"rId":24,"gId":40,"sId":50,"disabled":true},
{"rId":24,"gId":39,"sId":18,"disabled":false}]
console.log(eliminateOpposites(arrOfObj));
It makes use of hashing, which leads to a O(n) algorithm instead of O(n2), which is the case with indexOf-style solutions.
JSON.stringify and JSON.parse are used to compose and decompose the composite key values. The string version serves as key in a Map, in which each entry logs a count of disabled versus enabled occurrences of the same key. The .filter() call kicks out the cases where the count of disabled and enabled occurrences is the same (could be 2 versus 2), and the final .map() turns the kay/value array back to the expected format.
Comments
You could two loops, one for collecting and one for filtering the array.
var data = [{ "rId": 24, "gId": 40, "sId": 20, "disabled": false }, { "rId": 24, "gId": 40, "sId": 19, "disabled": false }, { "rId": 24, "gId": 40, "sId": 50, "disabled": false }, { "rId": 24, "gId": 40, "sId": 20, "disabled": true }, { "rId": 24, "gId": 40, "sId": 19, "disabled": true }, { "rId": 24, "gId": 40, "sId": 50, "disabled": true }, { "rId": 24, "gId": 39, "sId": 18, "disabled": false }],
hash = Object.create(null),
getKey = function (o) { return ["rId", "gId", "sId"].map(function (k) { return o[k]; }).join('|'); },
result;
data.forEach(function (a) {
var key = getKey(a);
hash[key] = (hash[key] || 0) + (a.disabled || -1);
});
result = data.filter(function (a) {
return hash[getKey(a)];
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
ES6 with Array#find
var data = [{ "rId": 24, "gId": 40, "sId": 20, "disabled": false }, { "rId": 24, "gId": 40, "sId": 19, "disabled": false }, { "rId": 24, "gId": 40, "sId": 50, "disabled": false }, { "rId": 24, "gId": 40, "sId": 20, "disabled": true }, { "rId": 24, "gId": 40, "sId": 19, "disabled": true }, { "rId": 24, "gId": 40, "sId": 50, "disabled": true }, { "rId": 24, "gId": 39, "sId": 18, "disabled": false }],
result = data.filter(a =>
!data.find(b => ["rId", "gId", "sId"].every(k =>
a[k] === b[k]
) && a.disabled !== b.disabled));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }