I want to remove an object in array if not present in another array. I tried to search and found similar question in this link but have a different array source.
Here is the example from link above :
var check = [1, 2, 3];
var allowed = [1];
var filtered = check.filter(function(item) {
return allowed.indexOf(item) > -1;
});
console.log(filtered);
Example above remove number in array check if not present in array allowed. In my case the source array contain an object like example below :
var check = [
{
name: 'Peter',
location: 'florida'
},
{
name: 'Robert',
location: 'California'
}
];
var allowed = [
{
name: 'Robert',
location: 'Boston'
}
];
var filtered = check.filter(function(item) {
return allowed.indexOf(item.name) > -1;
});
console.log(filtered);
I tried to run the code and the result is an empty array.
Result i expect :
[
{
name: 'Robert',
location: 'California'
}
]
Anyone can please help me to make the result as i expect?
5 Answers 5
You can use Array#find()
var check = [{
name: 'Peter',
location: 'florida'
},
{
name: 'Robert',
location: 'California'
}
];
var allowed = [{
name: 'Robert',
location: 'Boston'
}];
var res = check.filter(function(cItem) {
return allowed.find(function(aItem) {
return cItem.name === aItem.name
})
})
console.log(res)
1 Comment
You can map allowed to just contain the criteria that you are looking for (name):
var allowed = [{
name: 'Robert',
location: 'Boston'
}]
.map(obj => obj.name);
That will create an array of just names which is easier to test the indexOf
Example:
var check = [{
name: 'Peter',
location: 'florida'
},
{
name: 'Robert',
location: 'California'
}
];
var allowed = [{
name: 'Robert',
location: 'Boston'
}]
.map(obj => obj.name);
var filtered = check.filter(function(item) {
return allowed.indexOf(item.name) > -1;
});
console.log(filtered);
1 Comment
You need to check against the item names in the allowed array.
Right now you're checking against the items in the allowed array, which type is an object.
Here's the problem: return allowed.indexOf(item.name) > -1;
Maybe this approach helps:
var check = [
{
name: 'Peter',
location: 'florida'
},
{
name: 'Robert',
location: 'California'
}
];
var allowed = [
{
name: 'Robert',
location: 'Boston'
}
];
function containsName(name, array){
return array.find(item => item.name === name);
}
var filtered = check.filter(function(item) {
return containsName(item.name, allowed)
});
console.log(filtered);
1 Comment
The following intersect function would intersect any key on any given array of objects:
var check = [
{ name:'Peter', location:'florida' },
{ name:'Robert', location:'California'}
];
var allowed = [
{ name:'Robert', location:'Boston' }
];
function intersect(check, allowed) {
var allowed_map = allowed.reduce(function(map, obj) {
Object.keys(obj).forEach(function(key) {
if (!map[key]) {
map[key] = [];
}
map[key].push(obj[key]);
});
return map;
}, {});
return check.filter(function(item) {
return Object.keys(item).find(function(key) {
return allowed_map[key].indexOf(item[key]) != -1;
})
});
}
var filtered = intersect(check, allowed);
var allowed2 = [{ name:'Bob', location:'California' }];
var filtered2 = intersect(check, allowed2);
console.log('filtered',filtered);
console.log('filtered2',filtered2);
Comments
There are multiple approaches depending on what you need.
- Dirty Check
- Specific Attribute Check
- Nested Object Check
Dirty Check
For a dirty check where the objects will have the same memory reference on both arrays you can do the following.
var firstPerson = {
name: 'Peter',
location: 'florida'
}
var secondPerson = {
name: 'Robert',
location: 'California'
}
var allowed = [secondPerson];
var check = [firstPerson, secondPerson];
var result = check.filter(item => allowed.includes(item));
console.log(result);
Specific Attribute Check
For an specific attribute check you can use find and compare the check and allowed, by an attribute like name or location
var check = [
{
name: 'Peter',
location: 'florida'
},
{
name: 'Robert',
location: 'California'
}
];
var allowed = [
{
name: 'Robert',
location: 'Boston'
}
];
var result = check.filter(checkPerson => allowed.find(allowPerson => allowPerson.name === checkPerson.name));
console.log(result);
Nested Object Check
For a nested object check you would require to check the items recursively, I use this utility I created some time ago called deepCompare, is an alternative to Lodash's isEqual that only weights 880B
var check = [
{
name: 'Peter',
location: {
street: "fridtjof nansens vei 8511",
city: "ågotnes",
state: "buskerud",
postcode: "8766",
coordinates: {
latitude: "50.4828",
longitude: "-84.6920"
}
}
},
{
name: 'Robert',
location: {
street: "schillerstraße 69",
city: "velburg",
state: "saarland",
postcode: 72100,
coordinates: {
latitude: "30.4655",
longitude: "9.1938"
}
}
}
];
var allowed = [
{
name: 'Robert',
location: {
street: "schillerstraße 69",
city: "velburg",
state: "saarland",
postcode: 72100,
coordinates: {
latitude: "30.4655",
longitude: "9.1938"
}
}
}
];
var result = check.filter(checkPerson => allowed.some(allowPerson => deepCompare(checkPerson, allowPerson)));
console.log(result);
<script>
/**
* Deep Compare
* @param { * } value first entry value
* @param { * } other second entry value
* @param { Boolean } sorted Sort any array before deep comparison
*/
const deepCompare = (value, other, sorted) => {
/**
* Compare possible primitives
* Object.is works like `===` but additionally differes positive from negative values
* I.E:
* Object.is(-0, 0) // False
* -0 === 0 // True
*/
if (Object.is(value, other)) return true;
/**
* Check if either value is undefined or the constructor is different for each value
* given the case return false
*/
if (!value || !other || value.constructor !== other.constructor) return false;
/**
* Check Object and Array deep comparisons
*/
switch (value.constructor) {
case Array:
/**
* Check if both values have the same amount of items
* if they don't immediatelly omit the comparison and return false
*/
if (value.length === other.length) { return deepArrayCompare(value, other, sorted); }
return false;
case Object:
/**
* Check if both values have the same amount of keys
* if they don't immediatelly omit the comparison and return false
*/
if (Object.keys(value).length === Object.keys(other).length) { return deepObjectCompare(value, other, sorted); }
return false;
}
return false;
};
/**
* Deep Object Compare
* @param { * } value first entry value
* @param { * } other second entry value
*
* 'deepArrayCompare(Object.keys(value), Object.keys(other), sorted)'
* This checks that both objects have the same keys
* I.E:
* deepArrayCompare(Object.keys({ a: 1, b: 2, c:3 }), Object.keys({ a: 10, b: 22, c: 54 }), true) // True
* deepArrayCompare(Object.keys({ a: 1, b: 2, c:3 }), Object.keys({ g: 1, f: 2, d: 3 }), true) // False
*
* 'Object.keys(value).every(key => deepCompare(value[key], other[key]))'
* This iterates on each key of the object over a 'every' comparison and performs a deepCompare on both values
*
*/
const deepObjectCompare = (value, other) => deepArrayCompare(Object.keys(value), Object.keys(other), true) && Object.keys(value).every(key => deepCompare(value[key], other[key]));
/**
* Deep Array Compare
* @param { * } value first entry value
* @param { * } other second entry value
* @param { Boolean } sorted Sort any array before deep comparison
*
* '(sorted && value.sort(), sorted && other.sort(), ...)'
* This manages the optional sorting through Comma Operator
*
* 'value.every((item, index) => deepCompare(item, other[index]))'
* This performs the deepComparison of values between both arrays
*/
const deepArrayCompare = (value, other, sorted) => (sorted && value.sort(), sorted && other.sort(), value.every((item, index) => deepCompare(item, other[index])));
</script>
filter, notindexOfreturn allowed.indexOf(item.name) > -1;is checking if a 'person object' is equal to the name