2

I've got two arrays of objects, the difference between them is only that arrayAfter will have an element added:

var arrayBefore = [
  {"name":"Alan","height":"171","weight":"66"},
  {"name":"Ben","height":"182","weight":"90"}
 ];

var arrayAfter= [
  {"name":"Alan","height":"171","weight":"66"},
  {"name":"Ben","height":"182","weight":"90"},
  {"name":"Chris","height":"163","weight":"71"}
 ];

"name" is always unique!

How can I find out which one is the element that has been added? I've tried ending up using nested for loops, but this seems overcomplicated.

I've also found the this nice idea:

var diff = $(arrayAfter).not(arrayBefore ).get();

However, that does not seem to work on arrays of objects straight ahead.

Is there some easy way to get the difference?

peter
  • 2,103
  • 7
  • 25
  • 51

4 Answers4

2

If only the name indicates uniqueness, you can do:

//Get a list of all the names in the before array
var beforeNames = arrayBefore.map(function(person) { return person.name });

//Filter the after array to only contain names not contained in the before array
var uniqueObjects = arrayAfter.filter(function(person) {
    return beforeNames.indexOf(person.name) === -1;
});

console.log(uniqueObjects); //[{"name":"Chris","height":"163","weight":"71"}]

Demo: http://jsfiddle.net/tehgc8L5/

tymeJV
  • 103,943
  • 14
  • 161
  • 157
  • Very cool and exactly what I was looking for, thank you very much. – peter Sep 03 '15 at 15:04
  • This works fine, but note that for large data sets, the array lookup (`indexOf`) will perform poorly. Using object properties should speed things up: http://jsbin.com/nakugapoga/edit?js,console – Cristian Lupascu Sep 03 '15 at 15:07
1

For a generic method you can combine Array.prototype.filter() with Array.prototype.reduce() which iterates over the object keys:

arrayAfter.filter(function(after) {
    return !arrayBefore.reduce(function(found, before) {
        if (!found) {
            found = true;
            for (key in before) {
                if (before.hasOwnProperty(key)) {
                    found = found && (before[key] === after[key]);
                }
            }
        }
        return found;
    }, false);
}); //[{name: "Chris", height: "163", weight: "71"}]
Etheryte
  • 24,589
  • 11
  • 71
  • 116
0

You can use Array.prototype.filter and filter out those elements in the previous array.

var differences = arrayAfter.filter(function(el) {
  return arrayBefore.indexOf(el) === -1;
});
Mike Cluck
  • 31,869
  • 13
  • 80
  • 91
  • Did I misunderstand the problem? – Mike Cluck Sep 03 '15 at 14:56
  • 1
    @Grimbode It works if both arrays contain the same instances of the objects. Whether that's true or not was not made clear. – Mike Cluck Sep 03 '15 at 14:57
  • 1
    @MikeC they have the same data but are not the same, try `({}) === ({})` – Hacketo Sep 03 '15 at 14:58
  • @Hacketo I understand how object comparisons work. What I'm saying is that this solution works fine if, say, `arrayAfter` is the result of copying `arrayBefore` and pushing other objects into it. – Mike Cluck Sep 03 '15 at 14:59
  • You can compare arrays of objects by value, by converting every object in both arrays to json. Then this `.indexOf` search will succeed. It's kinda slow, but easy to code. – Shilly Sep 03 '15 at 15:00
0

I believe jQuery will have nothing that will directly solve your problem here. Your problem being comparing objects for equality.

I am assuming that name is unique. If not, for this method you will need a unique identifier for data. If you absolute do not have one then you could concat all data to get one.

// first make a map of objects in before
var before = {};
arrayBefore.forEach(function(o){
   before[o.name] = o;
});

// now we get the elements of after that do not exist in our hashmap
var result = arrayAfter.filter(function(o){
    return !(o.name in before);
});

You can obviously wrap this up in a general function.

UnknownFury
  • 304
  • 1
  • 12