Charlie Davies
Charlie Davies

Reputation: 1834

finding the difference in two arrays of hashes

I have two Arrays oldArray and newArray. When a new value gets put into newArray I want to compare against oldArray and pull out the new value.

In these arrays I am storing hashes.

For example.

oldArray = []
newArray = [{"one": 1}]

I need to find the new element, which is {"one": 1}

Using underscore.js I can do something like this:

newElement = _.difference(newValue, oldValue)

That works fine the first time, but when I go back and add more to the arrays:

oldArray = [{"one": 1}]
newArray = [{"one": 1},{"two": 2}]

And do the same thing newElement = _.difference(newValue, oldValue)

I get [{"one": 1},{"two": 2}] coming back as new objects... Is it because I am comparing objects and not values? Is there a better way to do this.

The above is an example but from my app I have pulled this from console

oldValue map.js:85
[Object]
0: Object
$$hashKey: "007"
address: "england"
latLng: GeoCode
__proto__: Object
length: 1
__proto__: Array[0]

newValue map.js:83
[Object, Object]

0: Object
$$hashKey: "007"
address: "england"
latLng: GeoCode
__proto__: Object

1: Object
$$hashKey: "009"
address: "france"
latLng: GeoCode
__proto__: Object
length: 2
__proto__: Array[0]

When I compare these two I get:

[Object, Object]
0: Object
$$hashKey: "007"
address: "england"
latLng: GeoCode
__proto__: Object

1: Object
$$hashKey: "009"
address: "france"
latLng: GeoCode
__proto__: Object
length: 2
__proto__: Array[0]

I am using AngularJS and Underscore in this project currently.

Maybe there is a much better of doing this. I just need to pull out the "different" object from that array. So I can use it to do something else. It will not always be the last element.

UPDATE

I have also tried JavaScript Array Set Mathematics Library and use .substract but with the same results. This must mean that the hashes are changing - but they dont look like it to me

To get these oldArray and newArray I am using an Angular $watch.

Upvotes: 2

Views: 2663

Answers (2)

nauce
nauce

Reputation: 46

I ran into a simular AngularJS challenge not long ago. While I'm not sure that I can give you the absolute BEST answer for how to manage this, here is what I can say worked for me:

First: Be sure you are using $watch properly. It takes 3 params:

  • watchExpression – {(function()|string)} – Expression that is evaluated on each $digest cycle. A change in the return value triggers a call to the listener. string: Evaluated as expression function(scope): called with current scope as a parameter.
  • listener(optional) – {(function()|string)=} – Callback called whenever the return value of the watchExpression changes. string: Evaluated as expression function(newValue, oldValue, scope): called with current and previous values as parameters.
  • objectEquality(optional) – {boolean=} – Compare object for equality rather than for reference.

The last piece is of particular importance. You want to be watching for objectEquality in your case, so be sure to use $watch like so:

$scope.$watch('watchObject', fn({}), true);

Note the use of true as the third param above. See more in the Angular Scope Docs.

Second: When diffing Angular objects, I think the answer around comparing the $$hashKeys could make a lot of sense. You might also consider writing your own diff function, depending on what you want to return. If you wanted to return the difference and you are only looking at diffing a basic object, try something like: jQuery objectDiff

Third: If you want to compare an Object with nested Objects and/or Arrays inside of it, things will get difficult. I wrote an unoptimized method of doing so, and I'll happily shed more light if you need it.

Good luck!

Upvotes: 0

Justin Blank
Justin Blank

Reputation: 1878

If $$hashKey is always unique, then you can create two objects and make the keys of the hashes their $$hashKey.

newObject[myObject["$$hashKey"]] = myObject;

Then

var difference = _.omit(newObject, _.keys(oldObject));

will give you an object containing that only contains the key/value pairs that were in the newObject but not the old.

If there's not a unique key, a less convenient way would be to serialize and deserialize the objects to strings, and then use _.difference.

Upvotes: 1

Related Questions