Ras
Ras

Reputation: 1031

How to remove object in array if not present in another array

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?

Upvotes: 1

Views: 3469

Answers (5)

garyvh2
garyvh2

Reputation: 11

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>

Upvotes: 1

Cornelius Lamb
Cornelius Lamb

Reputation: 74

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

Upvotes: 1

charlietfl
charlietfl

Reputation: 171669

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)

Upvotes: 4

rubentd
rubentd

Reputation: 1275

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

Upvotes: 2

KevBot
KevBot

Reputation: 18898

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

Upvotes: 3

Related Questions