比较两个包含对象的数组,以便计算更改的内容?

时间:2016-12-13 13:14:04

标签: javascript lodash

使用平面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}

修改

由于我的问题得到了很好的答案,我决定在服务器端和客户端测试它们。以下是我使用json-generator生成10 000条记录的json文件后得到的结果:

节点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差异似乎不起作用,在我放弃之前,我最多只能使用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');

5 个答案:

答案 0 :(得分:3)

使用_.differenceBy

var res = _.differenceBy(after, before, 'age');

答案 1 :(得分:1)

您可以将Array.filterArray.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;
}

答案 2 :(得分:1)

你也可以使用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);

答案 3 :(得分:1)

假设数组索引保持不变:

&#13;
&#13;
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));
&#13;
&#13;
&#13;

答案 4 :(得分:0)

我尝试使用下划线并且工作正常

  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)