Сравните два массива, содержащих объекты, чтобы вычислить, что изменилось?
Используя простой 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}
РЕДАКТИРОВАТЬ:
Поскольку я получил такой хороший вариант ответов на мой вопрос, я решил протестировать их все на стороне сервера и клиента. Вот что я получил после использования http://www.json-generator.com/ для создания файла 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');
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;
}
Использование _.differenceBy
var res = _.differenceBy(after, before, 'age');
Для сравнения вы также можете использовать метод lodash lower, вот код, который я сделал для вашего примера, который возвращает то, что вы хотите в этом 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);
Предполагается, что индексирование массива остается прежним:
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));
Я попытался с помощью подчеркивания, и он отлично работает
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)