0

I have 2 arrays:

var yin =  [{"_id": "11111", "name": "blue"}];
var yang = [{"_id": "11111", "name": "blue"}, {"_id": "22222", "name": "red"}];

I try and filter out the following like so:

var yang = yang.filter(function(e){ return this.indexOf(e) < 0; }, yin);

For some reason, indexOf(e) is returning -1 where I know it is the exact same data. The only thing I can think of is there is some relational (probably not the right term) data that is lying underneath that makes it seem like they are not the same since the objects are coming from completely different database sources.

Is there another method to do filter out the same data out of an array of objects that come from different sources?

I know this filter function works because if I push data using .push() it will filter out just fine.

bryan
  • 8,879
  • 18
  • 83
  • 166

5 Answers5

1

The problem is that they don't have the same objects.

They have objects that look the same.

As a simple example, check this out:

console.log({} == {});
console.log({} === {});

Notice, even though those objects look exactly the same, they aren't equal. Unlike primitives (string, number), objects are all unique from one another.

What you need to do instead is implement your own contains() function that will do a comparison of each property in the object:

const yin =  [{"_id": "11111", "name": "blue"}];
const yang = [{"_id": "11111", "name": "blue"}, {"_id": "22222", "name": "red"}];

function contains(arr, el) {
  return arr.some(i => equal(i, el));
}

function equal(a, b) {
  return Object.keys(a).length === Object.keys(b).length
    && Object.entries(a).every(([key, val]) => a[key] === b[key]);
}

// or !contains() if you want the difference
const result = yang.filter(function(el) { return contains(this, el) }, yin);

console.log(result);

The equal() function there only does a shallow comparison. If the objects are more complex, you'll want something that'll do a deep equals and recurse through all elements. Luckily, there are lots of options for this function already implemented in many popular libraries and standalone Node modules, so you don't have to implement it yourself.

samanime
  • 25,408
  • 15
  • 90
  • 139
  • Thank you for taking the time to write out a thoughtful explanation. While you're answer does work perfectly I like the simplicity of Gabrieles a little better. – bryan Jun 01 '18 at 14:30
1

The problem is that two distinct object will never be equal in the sense you mean. You will need to do a deep compare of the objects (manually) or if it suits your needs you can check for equal _id properties.

var yin =  [{"_id": "11111", "name": "blue"}];
var yang = [{"_id": "11111", "name": "blue"}, {"_id": "22222", "name": "red"}];

yang = yang.filter(function(e){ 
return this.findIndex(function(y){return y._id === e._id}) < 0; }, yin);

console.log(yang);
Gabriele Petrioli
  • 191,379
  • 34
  • 261
  • 317
0

The problem:

var yin =  [{"_id": "11111", "name": "blue"}];
yin.indexOf({"_id": "11111", "name": "blue"}) // return -1

So, I recommend to use a new function for filter the fields you need.

With Arrow Function:

yang.filter( e => yin.some(a => (a._id == e._id && a.name == e.name)));

Without Arrow Function:

yang.filter( function(elementYang) {
    return yin.some(function(elementYing) {
        return (elementYang._id == elementYing._id) && (elementYang._name == elementYing._name);
    });
});
Alexander
  • 90
  • 1
  • 3
  • 11
0

This will work.

var new = yang.filter((yang) => {
    for (let i = 0; i < yin.length; i++) {
      if (yin[i]._id==yang._id) {
        return yang;
      }
    }
  });
Pravin
  • 195
  • 1
  • 6
0

You need the sam object reference for comparing objects.

var object = { _id: "11111", name: "blue" },
    yin =  [object],
    yang = [object, { _id: "22222", name: "red" }];

yang = yang.filter(function(e){ return this.indexOf(e) < 0; }, yin);

console.log(yang)

Without object reference by assiming the same keys of the objects.

var yin =  [{ _id: "11111", name: "blue" }],
    yang = [{ _id: "11111", name: "blue" }, { _id: "22222", name: "red" }];

yang = yang.filter(o => !yin.some(p => Object.keys(o).every(k => o[k] === p[k])));

console.log(yang);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392