Используя простой JavaScript или используя lodash, это самый простой способ (в надежде, что у lodash есть функция), в котором я сравниваю следующие массивы и возвращаю значение, которое изменилось:

< Сильный > До

[
  {id: 0, name: 'Bob', age: 27},
  {id: 1, name: 'Frank', age: 32},
  {id: 2, name: 'Joe', age: 38}
]

< Сильный > После

[
  {id: 0, name: 'Bob', age: 27},
  {id: 1, name: 'Frank', age: 33},
  {id: 2, name: 'Joe', age: 38}
]

Итак, до и после Фрэнку сейчас 33 года, так как я могу просто вернуться:

{id: 1, name: 'Frank', age: 33}

Или более желаемый результат:

{id: 1, age: 33}

< Сильный > EDIT :

Получив такой хороший вариант ответов на мой вопрос, я решил протестировать их все на стороне сервера и клиента. Вот что я получил после использования json-generator для создания файла json из 10 000 записей:

Узел 7.1.0 .

David Domain. (Flat JS filter & some): 3.396
Result: { id: 1, name: 'Frank', age: 33 }
Ben Aston (Flat JS nested itteration): 4.359
Result: { age: 33, id: 1 }
Gille Q. (Lodash reduce): 21.335
Result: { id: 1, age: 33 }
Stasovlas. (Lodash differenceBy): 1.442
Result: []  
Vignesh Murugan. (Lodash findWhere): 0
Result: _.findWhere is not a function

Firefox 50.0.2 .

David Domain. (Flat JS filter & some): 6.695
Result: { id: 1, name: 'Frank', age: 33 }
Ben Aston (Flat JS nested itteration): 10.594
Result: { age: 33, id: 1 }
Gille Q. (Lodash reduce): 40.085
Result: { id: 1, age: 33 }
Stasovlas. (Lodash differenceBy): 6.499
Result: []

Интересно отметить, что Lodash diffBy, похоже, не работает, когда вы имеете дело с большими объемами данных, в лучшем случае я мог бы заставить это работать только с 3 записями, прежде чем я сдался.

@Vignesh, должно быть, когда-то работал с Underscore, но я не собираюсь рассказывать об этом, поскольку все изменилось, и теперь мы используем Lodash.

Вот код, который я использовал для тестирования, который используется для своевременного отслеживания количества времени, затраченного на выполнение функции, затем 1000 раз зацикливается, чтобы получить общее время выполнения функции 1000 раз, затем делится на 1000, чтобы получить среднее количество времени, затраченного на выполнение. (в мс) для выполнения функции:

var fs = require('fs');
var timely = require('timely');
var _ = require('lodash');

// Ben Aston
var ben_aston = function (a, b) {
  return a.reduce((p,c,i)=>{
    var diff = objDiff(c, b[i]);
    diff && p.push(diff);
    return p;
  }, [])
}
function objDiff(a, b) {
  var diff = Object.keys(a).reduce((p,c,i)=>{
    if (a[c] === b[c]) {
      return p;
    }
    p[c] = b[c];
    return p;
  }, {});
  if (!Object.keys(diff).length) {
    return;
  }
  diff.id = a.id;
  return diff;
}
var ben_astonT = timely(ben_aston);


// Gille Q.
var gille_q = function (before, after) {
  return _.reduce(before, function(result, value, key) {
    return _.isEqual(value, after[key]) ?
    result : result.concat({id: after[key].id, age: after[key].age});
  }, []);
}
var gille_qT = timely(gille_q);


// David Domain
var david_domain = function (before, after) {
  return after.filter( function( p, idx ) {
    return Object.keys(p).some( function( prop ) {
      return p[prop] !== before[idx][prop];
    })
  })
}
var david_domainT = timely(david_domain);


// Stasovlas
var stasovlas = function (before, after) {
  return _.differenceBy(after, before, 'age');
}
var stasovlasT = timely(stasovlas);


// Vignesh Murugan
var vignesh_murugan = function (before, after) {
  before.forEach((current) => {
    var after = _.findWhere(after,{id : current.id});
    if(!_.isEqual(after , current)) {
      return _.pick(after,"id","name");
    }
  });
}
var vignesh_muruganT = timely(vignesh_murugan);


// Load the data
var before = JSON.parse(fs.readFileSync('./before.json', 'utf8'));
var after = JSON.parse(fs.readFileSync('./after.json', 'utf8'));

// Open average tracking
var ben_aston_ave = 0,
    gille_q_ave = 0,
    david_domain_ave = 0,
    stasovlas_ave = 0,
    vignesh_murugan_ave = 0;

// Do test
for (i = 0; i < 1000; i++) {
  // Ben Aston
  ben_astonT(before, after);
  ben_aston_ave += ben_astonT.time;

  // Gille Q.
  gille_qT(before, after);
  gille_q_ave += gille_qT.time;

  // David Domain
  david_domainT(before, after);
  david_domain_ave += david_domainT.time;

  // Stasovlas
  stasovlasT(before, after);
  stasovlas_ave += stasovlasT.time;

  // Vignesh Murugan
  // vignesh_muruganT(before, after);
  // vignesh_murugan_ave += vignesh_muruganT.time;
}

// Calc averages
ben_aston_ave = ben_aston_ave / 1000;
gille_q_ave = gille_q_ave / 1000;
david_domain_ave = david_domain_ave / 1000;
stasovlas_ave = stasovlas_ave / 1000;
vignesh_murugan_ave = vignesh_murugan_ave / 1000;


console.log('David Domain. (Flat JS filter & some): '+david_domain_ave);
console.log('Result: { id: 1, name: \'Frank\', age: 33 }');
console.log('Ben Aston (Flat JS nested itteration): '+ben_aston_ave);
console.log('Result: { age: 33, id: 1 }');
console.log('Gille Q. (Lodash reduce): '+gille_q_ave);
console.log('Result: { id: 1, age: 33 }');
console.log('Stasovlas. (Lodash differenceBy): '+stasovlas_ave);
console.log('Result: []');
console.log('Vignesh Murugan. (Lodash findWhere): '+vignesh_murugan_ave);
console.log('Result: _.findWhere is not a function');
4
Craig van Tonder 13 Дек 2016 в 16:14

5 ответов

Лучший ответ

Вы можете использовать Array.filter с Array.some, который даст вам новый массив с измененными элементами.

Может быть, что-то вроде этого:

var before = [
  {id: 0, name: 'Bob', age: 27},
  {id: 1, name: 'Frank', age: 32},
  {id: 2, name: 'Joe', age: 38}
]

var after = [
  {id: 0, name: 'Bobb', age: 27},
  {id: 1, name: 'Frank', age: 33},
  {id: 2, name: 'Joe', age: 38}
]

var changed = after.filter( function( p, idx ) {
  return Object.keys(p).some( function( prop ) {
    return p[prop] !== before[idx][prop];
  })
})

console.log(changed)
.as-console-wrapper {
  max-height: 100% !important;
}
1
DavidDomain 13 Дек 2016 в 13:32

Вы также можете использовать метод lodash reduce для сравнения, вот код, который я сделал для вашего примера, который возвращает то, что вы хотите в этом jsfiddle:

https://jsfiddle.net/7rf9bphL/1/

var a = [
    {id: 0, name: 'Bob', age: 27},
    {id: 1, name: 'Frank', age: 32},
    {id: 2, name: 'Joe', age: 38}];

var b = [
    {id: 0, name: 'Bob', age: 27},
    {id: 1, name: 'Frank', age: 33},
    {id: 2, name: 'Joe', age: 38}];

var result = _.reduce(a, function(result, value, key) {
    return _.isEqual(value, b[key]) ?
        result : result.concat({id: b[key].id, age: b[key].age});
}, []);
console.log("result", result);
1
Gille Q. 13 Дек 2016 в 13:37

Использовать _.differenceBy

var res = _.differenceBy(after, before, 'age');
3
stasovlas 13 Дек 2016 в 13:25

Предполагается, что индексирование массива остается прежним:

function diff(a, b) {
    return a.reduce((p,c,i)=>{
        var diff = objDiff(c, b[i]);
        diff && p.push(diff);
        return p;
    }, [])
}
function objDiff(a, b) {
    var diff = Object.keys(a).reduce((p,c,i)=>{
        if (a[c] === b[c]) {
            return p;
        }
        p[c] = b[c];
        return p;
    }, {});
    if (!Object.keys(diff).length) {
        return;
    }
    diff.id = a.id;
    return diff;
}

const before = [{
    id: 0, name: 'Bob', age: 27 }, {
    id: 1, name: 'Frank', age: 32 }, {
    id: 2, name: 'Joe', age: 38 }]
const after = [{
    id: 0, name: 'Bob', age: 27 }, {
    id: 1, name: 'Frank', age: 33 }, {
    id: 2, name: 'Joe', age: 38 }];

console.log(diff(before, after));
1
52d6c6af 13 Дек 2016 в 13:41

Я попытался с помощью подчеркивания, и он отлично работает

  var x = [
  {id: 0, name: 'Bob', age: 27},
  {id: 1, name: 'Frank', age: 32},
  {id: 2, name: 'Joe', age: 38}
]

var y = [
  {id: 0, name: 'Bob', age: 27},
  {id: 1, name: 'Frank', age: 33},
  {id: 2, name: 'Joe', age: 38}
]

  x.forEach((current) => {
    var after = _.findWhere(y,{id : current.id})
    if(!_.isEqual(after , current)){
      console.log(_.pick(after,"id","name"))
    }
  })

Вот решение Lodash

var difference = [];

x.forEach((current) => {
  var after = _.find(y,{id : current.id})
  if(!_.isEqual(after , current)){
    difference.push(_.pick(after,"id","name"))
  }
})

console.log(difference)
0
Vignesh Murugan 14 Дек 2016 в 10:12