对象数组与lodash的深度比较

Array of object deep comparison with lodash

我有 2 个对象数组,我将与 lodash

进行深入比较

但是,我有一个问题:

> var x = [{a:1, b:2}, {c:3, d:4}];
> var y = [{b:2, a:1}, {d:4, c:3}];
> _.difference(x,y, _.isEqual);
[ { a: 1, b: 2 }, { c: 3, d: 4 } ]

我应该如何比较才能看到两者相等?

你可以使用differenceWith() with an isEqual() comparator, and invoke isEmpty来检查它们是否相等。

var isArrayEqual = function(x, y) {
  return _(x).differenceWith(y, _.isEqual).isEmpty();
};

var result1 = isArrayEqual(
  [{a:1, b:2}, {c:3, d:4}],
  [{b:2, a:1}, {d:4, c:3}]
);

var result2 = isArrayEqual(
  [{a:1, b:2, c: 1}, {c:3, d:4}],
  [{b:2, a:1}, {d:4, c:3}]
);

document.write([
  '<div><label>result1: ', result1, '</label></div>',
  '<div><label>result2: ', result2, '</label></div>',
].join(''));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.11.2/lodash.js"></script>

更新 2018 年 6 月 22 日

此更新是对以下评论的回应:

@ryeballar if any of the array is undefined it returns true. How would you solve this. Thanks in advance buddy

differenceWith 文档中所述:

The order and references of result values are determined by the first array.

这意味着只要第一个数组中的所有项都与第二个数组中的所有其他项匹配,那么 differenceWith 调用的结果数组将为空。

真正解决问题的替代解决方案是使用 xorWith() 和上述解决方案中相同的函数链。

var isArrayEqual = function(x, y) {
  return _(x).xorWith(y, _.isEqual).isEmpty();
};

var result1 = isArrayEqual(
  [{a:1, b:2}, {c:3, d:4}],
  [{b:2, a:1}, {d:4, c:3}]
);

var result2 = isArrayEqual(
  [{a:1, b:2, c: 1}, {c:3, d:4}],
  [{b:2, a:1}, {d:4, c:3}]
);

var result3 = isArrayEqual(
  [{a:1, b:2, c: 1}, {c:3, d:4}],
  [{b:2, a:1}, {d:4, c:3}, undefined]
);

console.log('result1:', result1);
console.log('result2:', result2);
console.log('result3:', result3);
.as-console-wrapper{min-height:100%;top:0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>

我更喜欢纯 JS,因为我没有耐心学习下划线或 lodash。所以我发明了我梦寐以求的东西。 Object.prototype.compare()。 v0.0.2 虽然只进行了浅层比较,但足以解决这个问题。

Object.prototype.compare = function(o){
  var ok = Object.keys(this);
  return typeof o === "object" && ok.length === Object.keys(o).length ? ok.every(k => this[k] === o[k]) : false;
};
var obj1 = {a:1,b:2,c:3},
    obj2 = {c:3,a:1,b:2},
    obj3 = {b:2,c:3,a:7};

document.write ("<pre>" + obj1.compare(obj2) + "</pre>\n");
document.write ("<pre>" + obj2.compare(obj3) + "</pre>\n");
document.write ("<pre>" + new Object({a:1, b:2, c:3}).compare({c:3,b:2,a:1,d:0}) + "</pre>\n");

酷...那么让我们继续这个问题...我想...既然我们已经有了 Object.prototype.compare(),那么 Array.prototype.compare() 的发明应该绝对没有害处。这次让它变得更聪明。它应该从对象中区分基元。另一件事是,数组是有序的;所以在我的书中 [1,2] 不等于 [2,1]。这也使工作更简单。

Object.prototype.compare = function(o){
  var ok = Object.keys(this);
  return typeof o === "object" && ok.length === Object.keys(o).length ? ok.every(k => this[k] === o[k]) : false;
};
Array.prototype.compare = function(a){
  return this.every((e,i) => typeof a[i] === "object" ? a[i].compare(e) : a[i] === e);
}
var x = [{a:1, b:2}, {c:3, d:4}],
    y = [{b:2, a:1}, {d:4, c:3}],
    a = [1,2,3,4,5],
    b = [1,2,3,4,5],
    p = "fourtytwo",
    r = "thirtyseven",
    n = 42,
    m = 37;
document.writeln(x.compare(y)); // the question is answered here
document.writeln(a.compare(b));
document.writeln(p.compare(r)); // these primitives end up at Object prototype
document.writeln(n.compare(m)); // so modify Object.prototype.compare () accordingly

按照@ryeballar 的回答,如果你只想导入特定的 lodash 方法,你可以使用这种表示法:

import { isEmpty, isEqual, xorWith } from 'lodash';


export const isArrayEqual = (x, y) => isEmpty(xorWith(x, y, isEqual));

只有在第二个数组中找到当前项目时,如果数组长度不同,上面 xorWithdifferenceWith 的两个答案都不会计算在内。

var isArrayEqual = function(x, y) {
  return _(x).xorWith(y, _.isEqual).isEmpty();
};

var result = isArrayEqual(
  [{a:1, b:2}],
  [{a:1, b:2}, {a:1, b:2}]
);


console.log('result should be false:', result);
.as-console-wrapper{min-height:100%;top:0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>

在那种特殊情况下,我们还必须比较两个数组的长度。

const isArrayEqual = function(x, y) {
  const isSameSize = _.size(x) === _.size(y);
  return isSameSize && _(x).xorWith(y, _.isEqual).isEmpty();
};

const result = isArrayEqual(
  [{a:1, b:2}],
  [{a:1, b:2}, {a:1, b:2}]
);


console.log('result should be false:', result);
.as-console-wrapper{min-height:100%;top:0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>