0

Array 1 is the result of the data from a localstorage

Array 2 is, for the same IDs (329, 307, 355), the result after treatment

So i need to compare both to notify what changed

Array 1 :

[{"329":["45738","45737","45736"]},{"307":["45467","45468"]},{"355":["47921"]}]

Array 2 :

[{"355":["47921","45922"]},{"329":["45738","45737","45736"]},{"307":[]}]

I need to compare Array 2 with Array 1 and extract differences.

In this example i want to have for result

[{"355":["45922"]},{"307":[]}]

I try to adapt this code :

var compareJSON = function(obj1, obj2) {
  var ret = {};
  for(var i in obj2) {
    if(!obj1.hasOwnProperty(i) || obj2[i] !== obj1[i]) {
      ret[i] = obj2[i];
    }
  }
  return ret;
};

Runnable:

var array1 = [{
    "329": ["45738", "45737", "45736"]
  }, {
    "307": ["45467", "45468"]
  }, {
    "355": ["47921"]
  }],
  array2 = [{
    "355": ["47921", "45922"]
  }, {
    "329": ["45738", "45737", "45736"]
  }, {
    "307": []
  }]

var compareJSON = function(obj1, obj2) {
  var ret = {};
  for (var i in obj2) {
    if (!obj1.hasOwnProperty(i) || obj2[i] !== obj1[i]) {
      ret[i] = obj2[i];
    }
  }
  return ret;
};

console.log(compareJSON(array1, array2));

But, either I have nothing or I have the whole table

bklups
  • 300
  • 1
  • 13

3 Answers3

1

your requirement(result) is not clear, but this will get you started.

var arr1 = [{ "329": ["45738", "45737", "45736"] }, { "307": ["45467", "45468"] }, { "355": ["47921"] }],
  arr2 = [{ "355": ["47921", "45922"] }, { "329": ["45738", "45737", "45736"] }, { "307": [] }];

var result = [];

arr2.forEach(obj => {
  var key = Object.keys(obj)[0];
  var match = arr1.find(o => o.hasOwnProperty(key));
  if (match) {
    var newObj = {};
    newObj[key] = obj[key].filter(s => match[key].indexOf(s) === -1);
    if (!obj[key].length || newObj[key].length) result.push(newObj)
  } else {
    result.push(Object.assign({}, obj));
  }
});

console.log(result);
Ja9ad335h
  • 4,995
  • 2
  • 21
  • 29
  • Just before the end of forEach i need to update `arr1` with data of `arr2`. So when i reload, `newObj` is reset to 0 (so, no differences yet). But is there a way to store differences in a variable, and concatenate it every time there are new differences ? I try to push in an array but it overwrites it – bklups May 23 '17 at 16:19
0

You could use a hash tbale and delete found items. If some items remains, then an empty array is taken to the result object.

var array1 = [{ 329: ["45738", "45737", "45736"] }, { 307: ["45467", "45468"] }, { 355: ["47921"] }],
    array2 = [{ 355: ["47921", "45922"] }, { 329: ["45738", "45737", "45736"] }, { 307: [] }],
    hash = {},
    result = [];

array1.forEach(function (o) {
    Object.keys(o).forEach(function (k) {
        hash[k] = hash[k] || {};
        o[k].forEach(function (a) {
            hash[k][a] = true;
        });
    });
});

array2.forEach(function (o) {
    var tempObject = {};
    Object.keys(o).forEach(function (k) {
        var tempArray = [];
        o[k].forEach(function (a) {
            if (hash[k][a]) {
                delete hash[k][a];
            } else {
                tempArray.push(a);
            }
        });
        if (tempArray.length || Object.keys(hash[k]).length) {
            tempObject[k] = tempArray;
        }
    });
    Object.keys(tempObject).length && result.push(tempObject);
});

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

I've used the deep-diff package in npm for this sort of thing before:

It may be more detail than you want though - here's an example from the readme of the output format:

[ { kind: 'E',
  path: [ 'name' ],
  lhs: 'my object',
  rhs: 'updated object' },
{ kind: 'E',
  path: [ 'details', 'with', 2 ],
    lhs: 'elements',
    rhs: 'more' },
{ kind: 'A',
  path: [ 'details', 'with' ],
  index: 3,
  item: { kind: 'N', rhs: 'elements' } },
{ kind: 'A',
  path: [ 'details', 'with' ],
  index: 4,
  item: { kind: 'N', rhs: { than: 'before' } } } ]

Checkout the readme on the github page linked above for details about what it all means, or try it out for yourself online using runkit

But in order for this to work you would have to do some sort of preprocessing:

Sort array based on first key of each element:

a1 = a1.sort((lhs, rhs) => {
  return parseInt(Object.keys(lhs)[0]) - parseInt(Object.keys(rhs)[0]);
})

If you sort both of the arrays by the first key of each element and then pass it to the diff tool, you get the following:

[
  {"kind":"A","path":[0,"307"],"index":0,"item":{"kind":"D","lhs":"45467"}},
  {"kind":"A","path":[0,"307"],"index":1,"item":{"kind":"D","lhs":"45468"}},
  {"kind":"A","path":[2,"355"],"index":1,"item":{"kind":"N","rhs":"45922"}}
]

If it were me I would probably merge all the array elements and diff the resulting object so you completely avoid any object order and duplicate key issues.

Alternative: merge array contents into one object

A naive merge might look like this:

a1Object = {}

a1.forEach((element) => { 
    Object.keys(element).forEach((key) => {
        a1Object[key] = element[key];
    });
})

Which produces the following diff:

[
  {"kind":"A","path":["307"],"index":0,"item":{"kind":"D","lhs":"45467"}},
  {"kind":"A","path":["307"],"index":1,"item":{"kind":"D","lhs":"45468"}},
  {"kind":"A","path":["355"],"index":1,"item":{"kind":"N","rhs":"45922"}}
]

Interpreting the diff output

  • there is a change in the Array value of 307 at index 0: 45467 has been Deleted
  • there is a change in the Array value of 307 at index 1: 45468 has been Deleted
  • there is a change in the Array value of 355 at index 1: 45467 has been Newly added
alexanderbird
  • 3,847
  • 1
  • 26
  • 35