如何比较 JavaScript 中的数组?

新手上路,请多包涵

我想比较两个数组……理想情况下,有效。没有什么花哨的,如果它们相同则为 true ,否则为 false 。毫不奇怪,比较运算符似乎不起作用。

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 对每个数组进行编码,但是是否有更快或“更好”的方法来简单地比较数组而无需遍历每个值?

原文由 Julian H. Lam 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 774
2 个回答

要比较数组,请遍历它们并比较每个值:

比较数组:

 // Warn if overriding existing method
 if(Array.prototype.equals)
 console.warn("Overriding existing Array.prototype.equals. Possible causes: New API defines the method, there's a framework conflict or you've got double inclusions in your code.");
 // attach the .equals method to Array's prototype to call it on any array
 Array.prototype.equals = function (array) {
 // if the other array is a falsy value, return
 if (!array)
 return false;

 // compare lengths - can save a lot of time
 if (this.length != array.length)
 return false;

 for (var i = 0, l=this.length; i < l; i++) {
 // Check if we have nested arrays
 if (this[i] instanceof Array && array[i] instanceof Array) {
 // recurse into the nested arrays
 if (!this[i].equals(array[i]))
 return false;
 }
 else if (this[i] != array[i]) {
 // Warning - two different object instances will never be equal: {x:20} != {x:20}
 return false;
 }
 }
 return true;
 }
 // Hide method from for-in loops
 Object.defineProperty(Array.prototype, "equals", {enumerable: false});

用法:

 [1, 2, [3, 4]].equals([1, 2, [3, 2]]) === false;
 [1, "2,3"].equals([1, 2, 3]) === false;
 [1, 2, [3, 4]].equals([1, 2, [3, 4]]) === true;
 [1, 2, 1, 2].equals([1, 2, 1, 2]) === true;

您可能会说“ 但是比较字符串要快得多 - 没有循环…… ”好吧,那么您应该注意有循环。第一个将 Array 转换为字符串的递归循环,第二个是比较两个字符串的递归循环。所以这种方法 比使用 string 更快

我相信大量的数据应该始终存储在数组中,而不是对象中。但是,如果您使用对象,它们也可以进行部分比较。

就是这样:

比较对象:

我在上面说过,两个对象 实例 永远不会相等,即使它们现在包含相同的数据:

 ({a:1, foo:"bar", numberOfTheBeast: 666}) == ({a:1, foo:"bar", numberOfTheBeast: 666}) //false

这是有原因的,因为例如 对象中可能存在私有变量。

但是,如果您只是使用对象结构来包含数据,则仍然可以进行比较:

 Object.prototype.equals = function(object2) {
 //For the first loop, we only check for types
 for (propName in this) {
 //Check for inherited methods and properties - like .equals itself
 //https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty
 //Return false if the return value is different
 if (this.hasOwnProperty(propName) != object2.hasOwnProperty(propName)) {
 return false;
 }
 //Check instance type
 else if (typeof this[propName] != typeof object2[propName]) {
 //Different types => not equal
 return false;
 }
 }
 //Now a deeper check using other objects property names
 for(propName in object2) {
 //We must check instances anyway, there may be a property that only exists in object2
 //I wonder, if remembering the checked values from the first loop would be faster or not
 if (this.hasOwnProperty(propName) != object2.hasOwnProperty(propName)) {
 return false;
 }
 else if (typeof this[propName] != typeof object2[propName]) {
 return false;
 }
 //If the property is inherited, do not check any more (it must be equa if both objects inherit it)
 if(!this.hasOwnProperty(propName))
 continue;

 //Now the detail check and recursion

 //This returns the script back to the array comparing
 /**REQUIRES Array.equals**/
 if (this[propName] instanceof Array && object2[propName] instanceof Array) {
 // recurse into the nested arrays
 if (!this[propName].equals(object2[propName]))
 return false;
 }
 else if (this[propName] instanceof Object && object2[propName] instanceof Object) {
 // recurse into another objects
 //console.log("Recursing to compare ", this[propName],"with",object2[propName], " both named \""+propName+"\"");
 if (!this[propName].equals(object2[propName]))
 return false;
 }
 //Normal value comparison for strings and numbers
 else if(this[propName] != object2[propName]) {
 return false;
 }
 }
 //If everything passed, let's say YES
 return true;
 }

但是,请记住,这是用于比较 JSON 之类的数据,而不是类实例和其他东西。如果您想比较更复杂的对象,请查看 此答案,它是超长功能

要使其与 Array.equals 一起使用,您必须稍微编辑原始函数:

 ...
 // Check if we have nested arrays
 if (this[i] instanceof Array && array[i] instanceof Array) {
 // recurse into the nested arrays
 if (!this[i].equals(array[i]))
 return false;
 }
 /**REQUIRES OBJECT COMPARE**/
 else if (this[i] instanceof Object && array[i] instanceof Object) {
 // recurse into another objects
 //console.log("Recursing to compare ", this[propName],"with",object2[propName], " both named \""+propName+"\"");
 if (!this[i].equals(array[i]))
 return false;
 }
 else if (this[i] != array[i]) {
 ...

为这两个功能做了一个小测试工具

奖励:带有 indexOfcontains 的嵌套数组

Samy Bencherif 为您在嵌套数组中搜索特定对象的情况准备 了有用的函数,这些函数可在此处获得: https ://jsfiddle.net/SamyBencherif/8352y6yw/

原文由 Tomáš Zato - Reinstate Monica 发布,翻译遵循 CC BY-SA 4.0 许可协议

虽然这仅适用于标量数组(请参阅下面的注释),但它是短代码:

 array1.length === array2.length && array1.every(function(value, index) { return value === array2[index]})

与上面相同,但在 ECMAScript 6 / CoffeeScript / TypeScript 中带有箭头函数:

 array1.length === array2.length && array1.every((value, index) => value === array2[index])

(注意:此处的“标量”表示可以使用 === 直接比较的值。因此:数字、字符串、引用对象、引用函数。有关比较运算符的更多信息,请参阅 MDN 参考)。

更新

从我在评论中读到的内容来看,对数组进行排序和比较可能会给出准确的结果:

 const array2Sorted = array2.slice().sort();
array1.length === array2.length && array1.slice().sort().every(function(value, index) {
    return value === array2Sorted[index];
});

例如:

 array1 = [2,3,1,4];
array2 = [1,2,3,4];

那么上面的代码会返回 true

原文由 user2782196 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题