Remove Multiple Objects from the group of Array - javascript

I would like to splice the whole Object inside the array "Docs > Exam" which has "Pass":"NO"
i have tried this
var docs = [
{"Id":1,"Name":"First","Exam":[{"Pass":"No"},{"Sub":"T1"}]},
{"Id":2,"Name":"Second","Exam":[{"Pass":"Yes"},{"Sub":"T2"}]},
{"Id":3,"Name":"Third","Exam":[{"Pass":"No"},{"Sub":"T3"}]}
];
for (var i = docs.length - 1; i >= 0; i--) {
for (var j = docs[i].Exam.length - 1; j >= 0; j--) {
if (docs[i].Exam[j].Pass == 'No') {
docs.splice(docs[i],1);
}
}
}
console.log(docs);
I need only the docs with this object only
{"Id":2,"Name":"Second","Exam":[{"Pass":"Yes"},{"Sub":"T2"}

This is very easy using filter and some:
docs = docs.filter(doc => doc.Exam.some(exam => exam.Pass === 'Yes'))

const isExamPassed = exam => exam.Pass === 'Yes';
1. docs.filter(doc => isExamPassed(doc.Exam[0]));
2. docs.map(doc => doc.Exam[0])
.filter(isExamPassed);

Use Array.filter API.
var docs = [{
"Id": 1,
"Name": "First",
"Exam": [{
"Pass": "No"
}, {
"Sub": "T1"
}]
},
{
"Id": 2,
"Name": "Second",
"Exam": [{
"Pass": "Yes"
}, {
"Sub": "T2"
}]
},
{
"Id": 3,
"Name": "Third",
"Exam": [{
"Pass": "No"
}, {
"Sub": "T3"
}]
}
];
console.log("Before Filtering: ", docs.length);
docs = docs.filter(function(doc, index) {
var bIsPass = true;
for (var j = doc.Exam.length - 1; j >= 0; --j) {
if (doc.Exam[j].Pass === "No") {
bIsPass = false;
break;
}
}
return bIsPass;
});
console.log("Before Filtering: ", docs.length);
console.log("Result :", docs);

Related

How to filter out objects if two keys are duplicate

const obj =
[
{
"id":"1",
"name":"a",
"email":"abc#gmail.com",
"expiryType":"premium"
},
{
"id":"2",
"name":"b",
"email":"abc#gmail.com",
"expiryType":"gold"
},
{
"id":"3",
"name":"b",
"email":"test#gmail.com",
"expiryType":"premium"
},
]
can somebody please help me how to filter out objects where email is same but i want to keep the one with expiry Type is premium ? How to achieve this using Javascript
Expected output would be
const obj =
[
{
"id":"1",
"name":"a",
"email":"abc#gmail.com",
"expiryType":"premium"
},
{
"id":"3",
"name":"b",
"email":"test#gmail.com",
"expiryType":"premium"
},
]
Assuming you want to keep the latest year's entry, you can keep a Map of the email addresses and years you've seen. See comments:
// The new list
const filtered = [];
// Known emails
const known = new Map();
// Loop through...
for (const entry of obj) {
// Get this email and expiry
const {email, expiryYear} = entry;
// Get the previous info if any
const previous = known.get(email);
if (previous) {
// If the previous one is older than this one,
// replace it with this one
if (previous.expiryYear < expiryYear) {
filtered[previous.index] = entry;
}
} else {
// Add this to the known list and the filtered array
known.set(email, {
index: filtered.length,
expiryYear
});
filtered.push(entry);
}
}
const obj = [
{
"id":"1",
"name":"a",
"email":"abc#gmail.com",
"expiryYear":"2020"
},
{
"id":"2",
"name":"a",
"email":"abc#gmail.com",
"expiryYear":"2019"
},
{
"id":"3",
"name":"b",
"email":"test#gmail.com",
"expiryYear":"2020"
},
];
// The new list
const filtered = [];
// Known emails
const known = new Map();
// Loop through...
for (const entry of obj) {
// Get this email and expiry
const {email, expiryYear} = entry;
// Get the previous info if any
const previous = known.get(email);
if (previous) {
// If the previous one is older than this one,
// replace it with this one
if (previous.expiryYear < expiryYear) {
filtered[previous.index] = entry;
}
} else {
// Add this to the known list and the filtered array
known.set(email, {
index: filtered.length,
expiryYear
});
filtered.push(entry);
}
}
console.log(filtered);
This has the advantage of not constantly re-scanning the new list for known entries.
You can filter out whole object based on unique key you want as below.
const obj =
[
{
"id": "1",
"name": "a",
"email": "abc#gmail.com",
"expiryType": "premium"
},
{
"id": "2",
"name": "b",
"email": "abc#gmail.com",
"expiryType": "gold"
},
{
"id": "3",
"name": "b",
"email": "test#gmail.com",
"expiryType": "premium"
}
]
function arrayUnique(arr, uniqueKey) {
const flagList = []
return arr.filter(function(item) {
if (flagList.findIndex(flagItem => flagItem[uniqueKey] === item[uniqueKey]) === -1) {
flagList.push(item)
return true
}
})
}
Method Calling....
let newObj = arrayUnique(obj,'email')
Output:
newObj = [
{
"id": "1",
"name": "a",
"email": "abc#gmail.com",
"expiryType": "premium"
},
{
"id": "3",
"name": "b",
"email": "test#gmail.com",
"expiryType": "premium"
}
]
Hope this helps.
You can do it simply with 2 loops. Maybe not the fastes but the simplest:
function deleteDouble(array, objectKey) {
for (var i = 0; i < array.length; i++) {
for (var j = 0; j < array.length; j++) {
if (i == j) {
continue;
}
if (array[i][objectKey] == array[j][objectKey]) {
array.splice(i, 1);
i = 0;
j = 0;
break;
}
}
}
return array;
}
deleteDouble(obj, "email");

Looking to filter array and make them into 2 arrays based on a flag if true or false

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);

Compare two arrays and update with the new values by keeping the existing objects using javascript

Below are my two arrays .I want to compare them and the resultant array should contain the updated values.Id's are common..
The arrays spans to n levels ie., there is no fixed levels..
The first array ie., the array before updation..
var parentArray1=[
{
"id": 1,
"name": "test",
"context": [
{
"id": 1.1,
"name": "test 1.1"
}
]
},
{
"id": 2,
"name": "test"
},
{
"id": 3,
"name": "test",
"context": [
{
"id": 3.1,
"name": "test 3.1"
}
]
},
{
"id": 4,
"name": "test"
}
]
The operations that i performed are
1.Adding a new Item
2.Updating an existing item
As a result of these two operations the changed values I will be getting in a different array..
ie.,
var changedArray=
[
{
"id": 1,
"name": "test1",
"context": [
{
"id": 1.1,
"name": "Changed test 1.1"
}
]
},
{
"id": 5,
"name": "test5"
}
]
Now I have written a generic function that loops through the parentArray1 and using the unique propertiesI need to either add a new item,if the item is there in the changedArray or update an existing item at any level
The resultant array should be ..
[
{
"id": 1,
"name": "test",
"context": [
{
"id": 1.1,
"name": "Changed test 1.1"
}
]
},
{
"id": 2,
"name": "test"
},
{
"id": 3,
"name": "test",
"context": [
{
"id": 3.1,
"name": "test 3.1"
}
]
},
{
"id": 4,
"name": "test"
},
{
"id": 5,
"name": "test5"
}
]
Generic function:
compareArray(parentArray1, changedArray, ["id"]);
function compareArray(array1, array2, propertyArray) {
var newItem = new Array();
array2.map(function(a1Item) {
array1.map(function(a2Item) {
/ If array loop again /
if (a2Item.constructor === Array) {
compareArray(a2Item, a1Item)
} else {
/ loop the property name to validate /
propertyArray.map(function(property) {
if (a2Item[property]) {
if (a2Item[property] === a1Item[property]) {
a2Item = a1Item
} else {
var isAvailable = _.find(newItem, function(item) {
return item[property] === a1Item[property]
})
if (!isAvailable) {
newItem.push(a1Item);
}
}
}
})
}
});
});
/ Insert the new item into the source array /
newItem.map(function(item) {
array1.push(item);
});
console.log("After Compare : " + array1);
}
I suggest to use a temporary object for the reference to the id and update if exist or push if not exist.
var parentArray1 = [{ "id": 1, "name": "test", "context": [{ "id": 1.1, "name": "test 1.1" }] }, { "id": 2, "name": "test" }, { "id": 3, "name": "test", "context": [{ "id": 3.1, "name": "test 3.1" }] }, { "id": 4, "name": "test" }],
changedArray = [{ "id": 1, "name": "test1", "context": [{ "id": 1.1, "name": "Changed test 1.1" }] }, { "id": 5, "name": "test5" }];
function insert(array, data) {
function iter(array) {
array.forEach(function (a) {
if (!('id' in a)) {
return;
}
if (o[a.id] !== a) {
o[a.id] = a;
}
Object.keys(a).forEach(function (k) {
Array.isArray(a[k]) && iter(a[k]);
});
});
}
var o = {};
iter(array);
data.forEach(function (a) {
if (o[a.id]) {
Object.keys(a).forEach(function (k) {
o[a.id][k] = a[k];
});
return;
}
array.push(a);
});
}
insert(parentArray1, changedArray);
document.write('<pre>' + JSON.stringify(parentArray1, 0, 4) + '</pre>');
This is what I came up with:
function sameKeys(o1, o2, keys) {
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
if (!o1.hasOwnProperty(key) || !o2.hasOwnProperty(key))
throw 'compared objects do not have the key ' + key;
if (o1[key] !== o2[key])
return false;
}
return true;
}
function isNothing(o) {
return typeof(o) === 'undefined' || o === null;
}
// this does not work if objects have functions as properties
function clone(o) {
if (isNothing(o))
return o;
return JSON.parse(JSON.stringify(o));
}
function extend(o1, o2, keys) {
if (isNothing(o2))
return;
if (isNothing(o1))
throw ('first parameter cannot be empty');
if (typeof(o1) != 'object' || typeof(o2) != 'object')
throw ('extend only works on objects');
Object.keys(o2).forEach(function (key) {
var newVal = o2[key];
if (o1.hasOwnProperty(key)) {
if (isNothing(newVal)) {
delete o1[key];
} else
if (Array.isArray(newVal)) {
compareArray(o1[key], newVal, keys);
} else {
switch (typeof(newVal)) {
case 'object':
extend(o1[key], newVal, keys);
break;
case 'boolean':
case 'number':
case 'string':
o1[key] = newVal;
break;
default:
throw 'not supported property type: ' + typeof(newVal);
}
}
} else {
o1[key] = clone(newVal);
}
});
}
function removeFromArray(arr, ids, keyArray) {
var indexes = [];
var it1s = arr.forEach(function (it, idx) {
if (sameKeys(ids, it, keyArray)) {
indexes.push(idx);
} else {
Object.keys(it).forEach(function (key) {
var newVal = it[key];
if (Array.isArray(newVal)) {
removeFromArray(it[key], ids, keyArray);
}
});
}
});
if (indexes.length) {
if (indexes.length > 1)
throw 'found multiple possible objects for the same key combination'
arr.splice(indexes[0], 1);
}
}
function compareArray(a1, a2, keyArray) {
a2.forEach(function (it2) {
var it1s = a1.filter(function (it) {
return sameKeys(it2, it, keyArray);
});
var it1;
if (!it1s.length) {
it1 = clone(it2);
a1.push(it1);
} else {
if (it1s.length > 1)
throw 'found multiple possible objects for the same key combination'
it1 = it1s[0];
extend(it1, it2, keyArray);
}
if (it2.removedIds) {
it2.removedIds.forEach(function (ids) {
removeFromArray(a1, ids, keyArray);
});
}
});
}
Use it with compareArray(parentArray1,changedArray,['id']);
Note that it would not work with objects that contain functions. Also, if the arrays would be large, perhaps a better solution is to sort both arrays by key, then always look from the last found object up. That's all I got for now.
Updated it with some concepts from Nina and some clearing of the code.
As I understood it, you only want to add properties. So extend({a: {b: 2}},{a:{c:3}}) will result in {a: {b:2,c:3}}. If this is not what you wanted, let me know.
I also added functionality for removing ids. If any of the objects in the array contains a removedIds array of the form [{id: 4},{id: 5}] then the items with those ids will be removed from the original array.
Slight modification on code, to satisfy your conditions. Try it!
function compareArray(originalArray, destinationArray, propertyArray) {
var newItem = new Array(), processedItem = new Array();
for (var i = 0; i < originalArray.length; i++) {
var sourceElement = originalArray[i];
for (var j = 0; j < destinationArray.length; j++) {
var destinationElement = destinationArray[j];
var isUpdated = false;
if (sourceElement.constructor === Array) {
compareArray(sourceElement, destinationElement, propertyArray);
} else {
/* loop the property name to validate */
propertyArray.map(function(property) {
if (sourceElement[property]) {
if (sourceElement[property] === destinationElement[property]) {
originalArray[i] = _.clone(destinationElement);
isUpdated = true;
return;
} else {
var isAvailable = _.find(newItem, function(item) {
return item[property] === destinationElement[property];
});
if (!isAvailable) {
var isAlreadyProcessed = _.find(processedItem, function(item) {
return item[property] === destinationElement[property];
});
if(!isAlreadyProcessed){
newItem.push(destinationElement);
}
}
}
}
});
}
if (isUpdated === true) {
break;
}
}
processedItem.push(sourceElement);
}
newItem.map(function(item) {
originalArray.push(item);
});
return originalArray;
}

Compare two objects in jQuery and get the difference [duplicate]

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);

Javascript: How to get object from object in an array

Sample data:
{
"data": [
{
"name": {
"full": "JOHN",
"rank": "SENIOR"
},
"mobile": "12345"
},
{
"name": {
"full": "HENRY",
"rank": "SENIOR"
},
"mobile": "67890"
},
{
"name": {
"full": "SAM",
"rank": "JUNIOR"
},
"mobile": "54321"
}
]
}
i'm trying to get the total number of senior members from the data sample above, and i can get the data.name and data.mobile, but i can't get the 'rank' data from the parent 'name' object. can anyone please guide me to obtain the rank data. below is my javascript:
function countRank(rank) {
var i;
for (i in rank.data) {
if (rank.data[i] == "SENIOR") {
i++;
}
document.getElementById('senior').innerHTML = 'Total senior members: ' + i;
}
}
<div id="senior"></div>
Try this JSFIDDLE
function countRank(rank) {
var k=0;
for (var i=0; i< rank.data.length; i++) {
if (rank.data[i].name.rank == "SENIOR") {
k++;
}
document.getElementById('senior').innerHTML = 'Total senior members: ' + k;
}
}
countRank(rank);
You can make something like this
var rank = {
"data": [{
"name": {
"full": "JOHN",
"rank": "SENIOR"
},
"mobile": "12345"
}, {
"name": {
"full": "HENRY",
"rank": "SENIOR"
},
"mobile": "67890"
}, {
"name": {
"full": "SAM",
"rank": "JUNIOR"
},
"mobile": "54321"
}]
};
function countRank(rank) {
var i = 0,
arr = rank.data;
for (var j = 0; j < arr.length; j++) {
for (var prop in arr[j]) {
if (arr[j][prop].rank == "SENIOR") {
i++;
}
document.getElementById('senior').innerHTML = 'Total senior members: ' + i;
}
}
}
countRank(rank);
myObject.data[0].name.rank
>>> "SENIOR"
Assuming that whole object is called obj:
var i=0;
for (i=0; i < obj.data.length; i++) {
console.log(obj.data[i].name.rank);
}
function countRank(rank) {
var count = 0;
var arr = rank.data;
for (var i=0; i<arr.length; i++) {
var name = arr[i].name;
if (name.rank == "SENIOR") {
count++;
}
}
alert(count);
}
I checked it and it worked well.
Using jQuery you can find rank from above data easily.
checkout sample on jsFiddle
http://jsfiddle.net/uBnfu/
$.each(jsonData.data, function (index, value) {
alert(value.name['rank']);
});

Categories

Resources