我想比较两个数组。。。理想地、有效地。没有什么稀奇古怪的,如果它们是相同的,那就是真的,如果不是,那就是假的。毫不奇怪,比较运算符似乎不起作用。
var a1 = [1,2,3];
var a2 = [1,2,3];
console.log(a1==a2); // Returns false
console.log(JSON.stringify(a1)==JSON.stringify(a2)); // Returns true
JSON对每个数组进行编码,但是否有一种更快或“更好”的方法来简单地比较数组而不必遍历每个值?
另一种代码很少的方法(使用Array reduce和Array includes):
arr1.length == arr2.length && arr1.reduce((a, b) => a && arr2.includes(b), true)
如果还要比较顺序的相等性:
arr1.length == arr2.length && arr1.reduce((a, b, i) => a && arr2[i], true)
长度检查确保一个数组中的元素集不仅仅是另一个数组的子集。缩减器用于遍历一个数组并搜索另一个数组中的每个项。如果找不到一项,reduce函数将返回false。在第一个示例中,正在测试是否包含元素第二个示例也检查订单
虽然这个问题的最佳答案是正确和良好的,但提供的代码可能需要一些改进。
下面是我自己比较数组和对象的代码。代码简短而简单:
Array.prototype.equals = function(otherArray) {
if (!otherArray || this.length != otherArray.length) return false;
return this.reduce(function(equal, item, index) {
var otherItem = otherArray[index];
var itemType = typeof item, otherItemType = typeof otherItem;
if (itemType !== otherItemType) return false;
return equal && (itemType === "object" ? item.equals(otherItem) : item === otherItem);
}, true);
};
if(!Object.prototype.keys) {
Object.prototype.keys = function() {
var a = [];
for (var key in this) {
if (this.hasOwnProperty(key)) a.push(key);
}
return a;
}
Object.defineProperty(Object.prototype, "keys", {enumerable: false});
}
Object.prototype.equals = function(otherObject) {
if (!otherObject) return false;
var object = this, objectKeys = object.keys();
if (!objectKeys.equals(otherObject.keys())) return false;
return objectKeys.reduce(function(equal, key) {
var value = object[key], otherValue = otherObject[key];
var valueType = typeof value, otherValueType = typeof otherValue;
if (valueType !== otherValueType) return false;
// this will call Array.prototype.equals for arrays and Object.prototype.equals for objects
return equal && (valueType === "object" ? value.equals(otherValue) : value === otherValue);
}, true);
}
Object.defineProperty(Object.prototype, "equals", {enumerable: false});
此代码支持嵌套在对象中的数组和嵌套在数组中的对象。
您可以在下面的repl中看到一整套测试并自己测试代码:https://repl.it/Esfz/3
本着原问题的精神:
我想比较两个数组。。。理想地、有效地。没有什么想象,如果它们是相同的,则为真,如果不是,则为假。
我一直在对这里提出的一些更简单的建议进行性能测试,结果如下(从快到慢):
而Tim Down(67%)
var i = a1.length;
while (i--) {
if (a1[i] !== a2[i]) return false;
}
return true
每(69%)用户2782196
a1.every((v,i)=> v === a2[i]);
DEI减少(74%)
a1.reduce((a, b) => a && a2.includes(b), true);
Gaizka Allende&vivek的join&toString(78%)
a1.join('') === a2.join('');
a1.toString() === a2.toString();
Victor Palomo创作的半到字符串(90%)
a1 == a2.toString();
radtek的stringify(100%)
JSON.stringify(a1) === JSON.stringify(a2);
注意,下面的示例假设数组是排序的,一维数组。对于一个常见的基准测试,长度比较已被删除(将a1.length==a2.length添加到任何建议中,您将获得约10%的性能提升)。选择最适合您的解决方案,了解每种解决方案的速度和局限性。
我在回答这个问题https://stackoverflow.com/a/10316616/711085(此后已标记为该答案的副本)。在那里,您将发现一个DeepEquals实现,它处理许多情况,例如Map和Set以及数组和对象的任意嵌套。其中对==的非传递性和记录==vs==的讨论尤为重要。
对于OP的特殊问题,如果数组仅由数字、字符串和布尔值组成,而没有NaN,那么对于足够大的数组,最有效的方法是预编译函数:
function areSimpleArraysEqual(a,b) {
// requires inputs be arrays of only Number, String, Boolean, and no NaN.
// will propagate error if either array is undefined.
if (a.length!=b.length)
return false;
for(let i=0; i<a.length; i++)
if (a[i]!==b[i]) // using === equality
return false;
return true;
}
如果一个人的业务逻辑一直附加到数组的末尾,通过检查(a.length>0&&a[a.length-1]!==b[b.length-1])是否返回false;,在一些罕见的情况下,可以实现平均情况O(1)和最坏情况O(N)。
var a1 = [1,2,3,6];
var a2 = [1,2,3,5];
function check(a, b) {
return (a.length != b.length) ? false :
a.every(function(row, index) {
return a[index] == b[index];
});
}
check(a1, a2);
//////或///////
var a1 = [1,2,3,6];
var a2 = [1,2,3,6];
function check(a, b) {
return (a.length != b.length) ? false :
!(a.some(function(row, index) {
return a[index] != b[index];
}));
}
check(a1, a2)