3

Immutable.js besides it's immutable also provide deep data structure comparison. It allow to boost React rendering performance since allow easily implement shouldComponentUpdate method or use react-immutable-render-mixin.

But, I only need deep comparison. Is there any solutions for deep data structure comparison without Immutable.js?


Update: I've got deep data tree with embedded objects/arrays. Each array entity in turn may contain another objects/arrays and so on and so forth. @MatthewHerbst I took a look at the link you post. That looks for me as a set of vehicles without tests. Also I'm not sure if that solutions can compare to pretty deep data trees, with embedded arrays inside arrays etc.

VB_
  • 45,112
  • 42
  • 145
  • 293
  • possible duplicate of [Object comparison in JavaScript](http://stackoverflow.com/questions/1068834/object-comparison-in-javascript) – Matthew Herbst Sep 23 '15 at 18:14
  • @MatthewHerbst that doesn't look as a duplicate for me. Look at my update – VB_ Sep 23 '15 at 18:56
  • fundamentally, your question is about how to compare two objects - the contents of those objects doesn't matter, they are still objects. The question I linked to makes it fairly clear that, using native JavaScript, this is **extremely** difficult. If you know everything inside your objects can be jsonified, using JSON to create strings of the objects and comparing is a decent approach (though you said in previous question you want to limit memory, and that approach could use a lot if the objects are big). I, and most others, recommend using a library function for deep object comparison. – Matthew Herbst Sep 24 '15 at 08:24
  • @MatthewHerbst yeah, that's exactly what I asked - what is the library for comparing objects besides Immutable.js? – VB_ Sep 24 '15 at 09:14
  • I thought you were trying to avoid libraries. [Lodash](https://lodash.com/docs#isEqual) is capable of it. There are several methods/libraries discussed in the linked ticket, and in the ticket that that ticket duplicates. – Matthew Herbst Sep 24 '15 at 09:19
  • @MatthewHerbst I'm already using lodash. Are you speaking about `_.isEqual`? Also can it be used as efficiently as `Immutable.js` at `shouldComponentUpdate` method? – VB_ Sep 24 '15 at 09:21
  • my link goes to `_.isEqual`, yes. Anything can be used with `shouldComponentUpdate`. The contents of `shouldComponentUpdate` is totally decided by you how it returns true/false. I have no idea about speed performance between Lodash and Immutable. I think you should go out and do your own tests and report back to us - you clearly know how to use jsperf. You mentioned in your other thread that the data isn't big. If it's not very big, I'm not sure why you are spending so much time on something that won't have much effect. – Matthew Herbst Sep 24 '15 at 10:01
  • @MatthewHerbst thank you, will investigate it – VB_ Sep 24 '15 at 12:03
  • You have an immutable.js alternative in [freezer.js](https://github.com/arqex/freezer). It doesn't compare objects itself but since it uses immutable data, comparing two objects in different states would be as easy as `state1.ob === state2.ob`. – marquex Oct 29 '15 at 18:21

2 Answers2

2

Writing your own deep-comparator is a trivial thing. Even, if you're not much into the recursion, you can just do it 'lazy way' by reusing immutableJS library (I assume, you don't mind using immutable.js on just one place) (es6 syntax used):

const deepEquals = (a, b) => immutable.is(immutable.fromJS(a), immutable.fromJS(b))

However, this solution is not very efficient for obvious reasons. If performance is your concern (but still, you dislike immutable.js for some reason), you may use the following approach:

  1. Write custom recursive deepEquals. Use the following trick: if a===b, then a and b deepEquals (no more checks are necessary, you can immediately return true. If a!==b, you must do a proper recursive for-each-key check though)

  2. In your code, avoid mutating things as much as possible (such that the trick from above will take effect as often as possible). This means,

instead of:

myObj[newkey] = newval

use:

let modifiedA = {...myObj, newkey: newval}

This way, creating modified versions of maps (and arrays) takes little more time, but the comparison can be MUCH faster (especially, if your data structure is quite nested, but your individual maps / arrays do not have many direct keys)

Tomas Kulich
  • 14,388
  • 4
  • 30
  • 35
  • Finally I understand that Immutable.js isn't only for deepEaual method. So I finished with Immutable.js now) I described the problem here http://stackoverflow.com/questions/32719425/react-use-or-not-to-use-immutable-js/33697128#33697128 – VB_ Nov 19 '15 at 12:13
0

One alternative is https://github.com/engineforce/ImmutableAssign, created by me, which is a lightweight immutable helper, which supports immutability and allows you to continue working with POJO (Plain Old JavaScript Object). Therefore you can check equality using === instead of deep object comparison.

E.g.,

var iassign = require("immutable-assign");
var _ = require("lodash");

var o1 = { a: { c: 1 }, b: [1, 2, 3] };
var o2 = iassign(
    o1, 
    function(o) { return o.b; },   // get property to be updated 
    function(b) {                  // update select property
        return _.map(b, function(i) { return i + 1; }); 
    }
);


// o2 =  { a: { c: 1 }, b: [2, 3, 4] }
// o1 is not modified

// o2 !== o1    
// o2.b !== o1.b

// o2.a === o1.a
engineforce
  • 2,840
  • 1
  • 23
  • 17
  • "However, you must disclose your affiliation in your answers" http://stackoverflow.com/help/promotion – Albin Jun 24 '16 at 11:50