如何在JavaScript中比较数组?

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

var a1 = [1,2,3];var a2 = [1,2,3];console.log(a1==a2);    // Returns falseconsole.log(JSON.stringify(a1)==JSON.stringify(a2));    // Returns true

JSON编码每个数组都可以,但是有没有更快或“更好”的方法来简单地比较数组,而无需遍历每个值?

1659134 次浏览

在与JSON.encode相同的行中,使用连接()。

function checkArrays( arrA, arrB ){
//check if lengths are differentif(arrA.length !== arrB.length) return false;

//slice so we do not effect the original//sort makes sure they are in order//join makes it a string so we can do a string comparevar cA = arrA.slice().sort().join(",");var cB = arrB.slice().sort().join(",");
return cA===cB;
}
var a = [1,2,3,4,5];var b = [5,4,3,2,1];var c = [1,2,3,4];var d = [1,2,3,4,6];var e = ["1","2","3","4","5"];  //will return true
console.log( checkArrays(a,b) );  //trueconsole.log( checkArrays(a,c) );  //falseconsole.log( checkArrays(a,d) );  //falseconsole.log( checkArrays(a,e) );  //true

唯一的问题是,如果你关心上次比较测试的类型。如果你关心类型,你将不得不循环。

function checkArrays( arrA, arrB ){
//check if lengths are differentif(arrA.length !== arrB.length) return false;
//slice so we do not effect the orginal//sort makes sure they are in ordervar cA = arrA.slice().sort();var cB = arrB.slice().sort();
for(var i=0;i<cA.length;i++){if(cA[i]!==cB[i]) return false;}
return true;
}
var a = [1,2,3,4,5];var b = [5,4,3,2,1];var c = [1,2,3,4];var d = [1,2,3,4,6];var e = ["1","2","3","4","5"];
console.log( checkArrays(a,b) );  //trueconsole.log( checkArrays(a,c) );  //falseconsole.log( checkArrays(a,d) );  //falseconsole.log( checkArrays(a,e) );  //false

如果顺序应该保持不变,那么它只是一个循环,不需要排序。

function checkArrays( arrA, arrB ){
//check if lengths are differentif(arrA.length !== arrB.length) return false;

for(var i=0;i<arrA.length;i++){if(arrA[i]!==arrB[i]) return false;}
return true;
}
var a = [1,2,3,4,5];var b = [5,4,3,2,1];var c = [1,2,3,4];var d = [1,2,3,4,6];var e = ["1","2","3","4","5"];
console.log( checkArrays(a,a) );  //trueconsole.log( checkArrays(a,b) );  //falseconsole.log( checkArrays(a,c) );  //falseconsole.log( checkArrays(a,d) );  //falseconsole.log( checkArrays(a,e) );  //false

不清楚“相同”是什么意思。例如,下面的数组ab是否相同(注意嵌套数组)?

var a = ["foo", ["bar"]], b = ["foo", ["bar"]];

这是一个优化的数组比较函数,它使用严格相等依次比较每个数组的相应元素,并且不会对本身就是数组的数组元素进行递归比较,这意味着对于上面的示例,arraysIdentical(a, b)将返回false。它适用于一般情况,而基于JSON和join()的解决方案不会:

function arraysIdentical(a, b) {var i = a.length;if (i != b.length) return false;while (i--) {if (a[i] !== b[i]) return false;}return true;};

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

比较数组:

// Warn if overriding existing methodif(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 arrayArray.prototype.equals = function (array) {// if the other array is a falsy value, returnif (!array)return false;// if the argument is the same array, we can be sure the contents are same as wellif(array === this)return true;// compare lengths - can save a lot of timeif (this.length != array.length)return false;
for (var i = 0, l=this.length; i < l; i++) {// Check if we have nested arraysif (this[i] instanceof Array && array[i] instanceof Array) {// recurse into the nested arraysif (!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 loopsObject.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;

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

我认为大量的数据应该总是存储在数组中,而不是对象中。但是,如果你使用对象,它们也可以部分比较。
方法如下:

比较对象:

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

({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 typesfor (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 differentif (this.hasOwnProperty(propName) != object2.hasOwnProperty(propName)) {return false;}//Check instance typeelse if (typeof this[propName] != typeof object2[propName]) {//Different types => not equalreturn false;}}//Now a deeper check using other objects property namesfor(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 notif (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 arraysif (!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 numberselse if(this[propName] != object2[propName]) {return false;}}//If everything passed, let's say YESreturn true;}

但是,请记住,这是用于比较JSON之类的数据,而不是类实例和其他东西。如果你想比较更复杂的对象,请查看这个答案和它的超长函数
要使用Array.equals进行此操作,您必须稍微编辑原始函数:

...// Check if we have nested arraysif (this[i] instanceof Array && array[i] instanceof Array) {// recurse into the nested arraysif (!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的嵌套数组

萨米·本谢里夫准备对于您在嵌套数组中搜索特定对象的情况有用的函数,可在此处使用:https://jsfiddle.net/SamyBencherif/8352y6yw/

在我的例子中,比较数组只包含数字和字符串。此函数将显示数组是否包含相同的元素。

function are_arrs_match(arr1, arr2){return arr1.sort().toString() === arr2.sort().toString()}

让我们测试它!

arr1 = [1, 2, 3, 'nik']arr2 = ['nik', 3, 1, 2]arr3 = [1, 2, 5]
console.log (are_arrs_match(arr1, arr2)) //trueconsole.log (are_arrs_match(arr1, arr3)) //false

这是我的解决方案:

/*** Tests two data structures for equality* @param {object} x* @param {object} y* @returns {boolean}*/var equal = function(x, y) {if (typeof x !== typeof y) return false;if (x instanceof Array && y instanceof Array && x.length !== y.length) return false;if (typeof x === 'object') {for (var p in x) if (x.hasOwnProperty(p)) {if (typeof x[p] === 'function' && typeof y[p] === 'function') continue;if (x[p] instanceof Array && y[p] instanceof Array && x[p].length !== y[p].length) return false;if (typeof x[p] !== typeof y[p]) return false;if (typeof x[p] === 'object' && typeof y[p] === 'object') { if (!equal(x[p], y[p])) return false; } elseif (x[p] !== y[p]) return false;}} else return x === y;return true;};

适用于任何嵌套数据结构,显然忽略对象的方法。甚至不要想用这个方法扩展Object.prototype,当我尝试过一次时,jQuery坏了;)

对于大多数数组,它仍然比大多数序列化解决方案快。它可能是对象记录数组最快的比较方法。

扩展托马斯·扎托的观点。托马斯的Array.prototype.compare实际上应该被称为Array.prototype.compare相同的。

它通过:

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

但失败于:

[[1, 2, [3, 2]],1, 2, [3, 2]].compareIdentical([1, 2, [3, 2],[1, 2, [3, 2]]])

这里是更好的(在我看来)版本:

Array.prototype.compare = function (array) {// if the other array is a falsy value, returnif (!array)return false;
// compare lengths - can save a lot of timeif (this.length != array.length)return false;
this.sort();array.sort();for (var i = 0; i < this.length; i++) {// Check if we have nested arraysif (this[i] instanceof Array && array[i] instanceof Array) {// recurse into the nested arraysif (!this[i].compare(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;}

基于TomášZato的回答,我同意只需迭代数组是最快的。此外(就像其他人已经声明的那样),该函数应该被称为equals/等于,而不是比较。有鉴于此,我修改了该函数以处理比较数组的相似性——即它们具有相同的元素,但无序——供个人使用,并认为我应该把它扔在这里给每个人看。

Array.prototype.equals = function (array, strict) {if (!array)return false;
if (arguments.length == 1)strict = true;
if (this.length != array.length)return false;
for (var i = 0; i < this.length; i++) {if (this[i] instanceof Array && array[i] instanceof Array) {if (!this[i].equals(array[i], strict))return false;}else if (strict && this[i] != array[i]) {return false;}else if (!strict) {return this.sort().equals(array.sort(), true);}}return true;}

此函数需要一个默认为true的附加严格参数。此严格参数定义数组是否需要在内容和这些内容的顺序上完全相等,或者只是包含相同的内容。

示例:

var arr1 = [1, 2, 3, 4];var arr2 = [2, 1, 4, 3];  // Loosely equal to 1var arr3 = [2, 2, 3, 4];  // Not equal to 1var arr4 = [1, 2, 3, 4];  // Strictly equal to 1
arr1.equals(arr2);         // falsearr1.equals(arr2, false);  // truearr1.equals(arr3);         // falsearr1.equals(arr3, false);  // falsearr1.equals(arr4);         // truearr1.equals(arr4, false);  // true

我还写了一个快速的jsfiddle函数和这个例子:
http://jsfiddle.net/Roundaround/DLkxX/

我的解决方案比较对象,而不是数组。这将与Tomáš的工作方式相同,因为数组是对象,但没有警告:

Object.prototype.compare_to = function(comparable){    
// Is the value being compared an objectif(comparable instanceof Object){        
// Count the amount of properties in @comparablevar count_of_comparable = 0;for(p in comparable) count_of_comparable++;        
// Loop through all the properties in @thisfor(property in this){            
// Decrements once for every property in @thiscount_of_comparable--;            
// Prevents an infinite loopif(property != "compare_to"){                
// Is the property in @comparableif(property in comparable){                    
// Is the property also an Objectif(this[property] instanceof Object){                        
// Compare the properties if yesif(!(this[property].compare_to(comparable[property]))){                            
// Return false if the Object properties don't matchreturn false;}// Are the values unequal} else if(this[property] !== comparable[property]){                        
// Return false if they are unequalreturn false;}} else {                
// Return false if the property is not in the object being comparedreturn false;}}}} else {        
// Return false if the value is anything other than an objectreturn false;}    
// Return true if their are as many properties in the comparable object as @thisreturn count_of_comparable == 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

我喜欢使用Underscore库进行数组/对象重编码项目……在Underscore和Lodash中,无论您是比较数组还是对象,它看起来都像这样:

_.isEqual(array1, array2)   // returns a boolean_.isEqual(object1, object2) // returns a boolean

这是一个CoffeeScript版本,对于那些喜欢它的人:

Array.prototype.equals = (array) ->return false if not array # if the other array is a falsy value, returnreturn false if @length isnt array.length # compare lengths - can save a lot of time
for item, index in @if item instanceof Array and array[index] instanceof Array # Check if we have nested arraysif not item.equals(array[index]) # recurse into the nested arraysreturn falseelse if this[index] != array[index]return false # Warning - two different object instances will never be equal: {x:20} != {x:20}true

所有学分都归@tomas-zato所有。

如果数组是普通的,顺序是物质,那么这两行可能会有所帮助

//Assumevar a = ['a','b', 'c']; var b = ['a','e', 'c'];
if(a.length !== b.length) return false;return !a.reduce(function(prev,next,idx, arr){ return prev || next != b[idx] },false);

Reduce遍历数组之一并返回“false”,如果“a”的至少一个元素不等于“b”的元素只需将其包装成函数

我认为这是使用JSON stringify最简单的方法,在某些情况下它可能是最好的解决方案:

JSON.stringify(a1) === JSON.stringify(a2);

这将对象a1a2转换为字符串,以便可以比较它们。在大多数情况下,顺序很重要,因为可以使用上述答案之一中显示的排序算法对对象进行排序。

请注意,您不再比较对象,而是比较对象的字符串表示形式。它可能不是您想要的。

此脚本比较对象、数组和多维数组

function compare(a,b){var primitive=['string','number','boolean'];if(primitive.indexOf(typeof a)!==-1 && primitive.indexOf(typeof a)===primitive.indexOf(typeof b))return a===b;if(typeof a!==typeof b || a.length!==b.length)return false;for(i in a){if(!compare(a[i],b[i]))return false;}return true;}

第一行检查它是否是原始类型。如果是,它比较两个参数。

如果它们是对象。它迭代对象并递归检查每个元素。

用法:

var a=[1,2,[1,2]];var b=[1,2,[1,2]];var isEqual=compare(a,b);  //true

此函数比较任意形状和直径的两个数组:

function equals(a1, a2) {
if (!Array.isArray(a1) || !Array.isArray(a2)) {throw new Error("Arguments to function equals(a1, a2) must be arrays.");}
if (a1.length !== a2.length) {return false;}
for (var i=0; i<a1.length; i++) {if (Array.isArray(a1[i]) && Array.isArray(a2[i])) {if (equals(a1[i], a2[i])) {continue;} else {return false;}} else {if (a1[i] !== a2[i]) {return false;}}}
return true;}

此外,我还根据需要将Thomas的解决方案转换为免费比较。

Array.prototype.equalsFreeOrder = function (array) {var isThisElemExist;if (!array)return false;
if (this.length != array.length)return false;
for (var i = 0; i < this.length; i++) {isThisElemExist = false;for (var k = 0; k < this.length; k++) {if (this[i] instanceof Array && array[k] instanceof Array) {if (this[i].equalsFreeOrder(array[k]))isThisElemExist = true;}else if (this[i] == array[k]) {isThisElemExist = true;}}if (!isThisElemExist)return false;}return true;}

如果您将摩卡这样的测试框架与断言库一起使用,您可以使用相等来比较数组。

expect(a1).to.deep.equal(a2)

仅当数组在相应索引处具有相等的元素时,才应返回true。

我们可以用函数式的方法,使用everyhttps://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/every

function compareArrays(array1, array2) {if (array1.length === array2.length)return array1.every((a, index) => a === array2[index])elsereturn false}
// testvar a1 = [1,2,3];var a2 = [1,2,3];
var a3 = ['a', 'r', 'r', 'a', 'y', '1']var a4 = ['a', 'r', 'r', 'a', 'y', '2']
console.log(compareArrays(a1,a2)) // trueconsole.log(compareArrays(a1,a3)) // falseconsole.log(compareArrays(a3,a4)) // false

实际的方式

我认为如果一个特定的实现是“正确的方式™”,而不是“错误的”解决方案,那么说它是“正确的方式”是错误的。Tomáš的解决方案相对于基于字符串的数组比较有明显的改进,但这并不意味着它在客观上是“正确的”。什么是?它是最快的吗?它是最灵活的吗?它是最容易理解的吗?它是调试最快的吗?它使用的操作最少吗?它有任何副作用吗?没有一个解决方案可以拥有所有东西中最好的。

Tomáš可以说他的解决方案很快,但我也会说它不必要地复杂。它试图成为适用于所有数组的一体化解决方案,无论嵌套与否。事实上,它甚至接受不仅仅是数组作为输入,并且仍然试图给出“有效”的答案。


泛型提供可重用性

我的回答将以不同的方式处理这个问题。我将从一个只涉及逐步遍历数组的通用arrayCompare过程开始。从那里,我们将构建其他基本的比较函数,如arrayEqualarrayDeepEqual

// arrayCompare :: (a -> a -> Bool) -> [a] -> [a] -> Boolconst arrayCompare = f => ([x,...xs]) => ([y,...ys]) =>x === undefined && y === undefined? true: Boolean (f (x) (y)) && arrayCompare (f) (xs) (ys)

在我看来,最好的代码甚至不需要注释,这也不例外。这里发生的事情太少了,你几乎可以毫不费力地理解这个过程的行为。当然,ES6的一些语法现在对你来说可能看起来很陌生,但这只是因为ES6相对较新。

正如类型所暗示的那样,arrayCompare采用比较函数f和两个输入数组xsys。在大多数情况下,我们所做的就是为输入数组中的每个元素调用f (x) (y)。如果用户定义的f返回false,我们会返回一个早期的false——这要归功于&&的短路评估。所以是的,这意味着比较器可以提前停止迭代,并在不必要时防止循环通过输入数组的其余部分。


严格比较

接下来,使用我们的arrayCompare函数,我们可以轻松创建我们可能需要的其他函数。

// equal :: a -> a -> Boolconst equal = x => y =>x === y // notice: triple equal
// arrayEqual :: [a] -> [a] -> Boolconst arrayEqual =arrayCompare (equal)
const xs = [1,2,3]const ys = [1,2,3]console.log (arrayEqual (xs) (ys))      //=> true// (1 === 1) && (2 === 2) && (3 === 3)  //=> true
const zs = ['1','2','3']console.log (arrayEqual (xs) (zs))      //=> false// (1 === '1')                          //=> false

arrayEqual可以用arrayCompare定义,并使用===(用于严格相等)比较ab的比较器函数。

请注意,我们还将equal定义为它自己的函数。这突出了arrayCompare作为高阶函数的作用,以在另一种数据类型(Array)的上下文中使用我们的一阶比较器。


松散比较

我们可以使用==轻松定义arrayLooseEqual。现在,当比较1(数字)和'1'(字符串)时,结果将是true

// looseEqual :: a -> a -> Boolconst looseEqual = x => y =>x == y // notice: double equal
// arrayLooseEqual :: [a] -> [a] -> Boolconst arrayLooseEqual =arrayCompare (looseEqual)
const xs = [1,2,3]const ys = ['1','2','3']console.log (arrayLooseEqual (xs) (ys))    //=> true// (1 == '1') && (2 == '2') && (3 == '3')  //=> true

深度比较(递归)

你可能已经注意到这只是浅层比较,托马斯的解决方案肯定是“正确的方式™”,因为它确实隐含了深度比较,对吧?

好吧,我们的arrayCompare过程足够通用,可以让深度相等测试变得轻而易举。

// isArray :: a -> Boolconst isArray =Array.isArray
// arrayDeepCompare :: (a -> a -> Bool) -> [a] -> [a] -> Boolconst arrayDeepCompare = f =>arrayCompare (a => b =>isArray (a) && isArray (b)? arrayDeepCompare (f) (a) (b): f (a) (b))
const xs = [1,[2,[3]]]const ys = [1,[2,['3']]]console.log (arrayDeepCompare (equal) (xs) (ys)) //=> false// (1 === 1) && (2 === 2) && (3 === '3')         //=> false
console.log (arrayDeepCompare (looseEqual) (xs) (ys)) //=> true// (1 == 1) && (2 == 2) && (3 == '3')                 //=> true

就这么简单。我们使用另一个高阶函数构建了一个深度比较器。这次我们使用一个自定义比较器包装arrayCompare,该比较器将检查ab是否是数组。如果是,请重新应用arrayDeepCompare,否则将ab比较到用户指定的比较器(f)。这使我们能够将深度比较行为与我们实际比较单个元素的方式分开。即,如上面的示例所示,我们可以使用equallooseEqual或我们制作的任何其他比较器进行深度比较。

因为arrayDeepCompare是柯里化的,我们也可以像前面的例子一样部分应用它

// arrayDeepEqual :: [a] -> [a] -> Boolconst arrayDeepEqual =arrayDeepCompare (equal)
// arrayDeepLooseEqual :: [a] -> [a] -> Boolconst arrayDeepLooseEqual =arrayDeepCompare (looseEqual)

对我来说,这已经比Tomáš的解决方案有了明显的改进,因为我可以根据需要为我的数组选择浅比较或深比较。


对象比较(示例)

现在,如果你有一个对象数组或其他东西怎么办?如果每个对象都有相同的id值,也许你想将这些数组视为“相等”…

// idEqual :: {id: Number} -> {id: Number} -> Boolconst idEqual = x => y =>x.id !== undefined && x.id === y.id
// arrayIdEqual :: [a] -> [a] -> Boolconst arrayIdEqual =arrayCompare (idEqual)
const xs = [{id:1}, {id:2}]const ys = [{id:1}, {id:2}]console.log (arrayIdEqual (xs) (ys)) //=> true// (1 === 1) && (2 === 2)            //=> true
const zs = [{id:1}, {id:6}]console.log (arrayIdEqual (xs) (zs)) //=> false// (1 === 1) && (2 === 6)            //=> false

就这么简单。在这里我使用了vanilla JS对象,但这种类型的比较器可以适用于任何对象类型;甚至你的自定义对象。Tomáš的解决方案需要完全重新设计以支持这种相等性测试

带有对象的深度数组?没问题。我们构建了高度通用的通用函数,因此它们可以在各种用例中工作。

const xs = [{id:1}, [{id:2}]]const ys = [{id:1}, [{id:2}]]console.log (arrayCompare (idEqual) (xs) (ys))     //=> falseconsole.log (arrayDeepCompare (idEqual) (xs) (ys)) //=> true

任意比较(示例)

或者如果你想做一些其他类型的完全任意的比较呢?也许我想知道每个x是否大于每个y

// gt :: Number -> Number -> Boolconst gt = x => y =>x > y
// arrayGt :: [a] -> [a] -> Boolconst arrayGt = arrayCompare (gt)
const xs = [5,10,20]const ys = [2,4,8]console.log (arrayGt (xs) (ys))     //=> true// (5 > 2) && (10 > 4) && (20 > 8)  //=> true
const zs = [6,12,24]console.log (arrayGt (xs) (zs))     //=> false// (5 > 6)                          //=> false

少即是多

你可以看到我们实际上用更少的代码做了更多的事情。arrayCompare本身没有什么复杂的,我们制作的每个自定义比较器都有一个非常简单的实现。

轻松地,我们可以准确地定义我们希望如何比较两个数组-浅,深,严格,松散,一些对象属性,或一些任意计算,或这些的任何组合-全部使用一个程序arrayCompare。甚至可以梦想一个RegExp比较器!我知道孩子们有多喜欢那些正则表达式…

这是最快的吗?不是。但可能也不需要。如果速度是衡量代码质量的唯一指标,那么很多很棒的代码都会被丢弃——这就是为什么我把这种方法称为0,或者更公平地说,是1种实用方式。这个描述适合这个答案,因为我并不是说这个答案只有与其他答案相比才实用;它在客观上是真实的。我们用非常少的代码获得了高度的实用性,并且非常容易推理。没有其他代码可以说我们不值得这个描述。

这是否意味着它是你的“正确”解决方案?这由0号来决定。没有人能为你做这件事;只有你知道自己的需求是什么。几乎在所有情况下,我更看重直接、实用和通用的代码,而不是聪明和快速的代码。你看重的可能不同,所以选择适合你的。


编辑

我以前的答案更侧重于将arrayEqual分解为小程序。这是一个有趣的练习,但不是解决这个问题的最佳(最实用)方法。如果你感兴趣,你可以查看这段修订历史。

var er = [{id:"23",name:"23222"}, {id:"222",name:"23222222"}];var er2 = [{id:"23",name:"23222"}, {id:"222",name:"23222222"}];
var result = (JSON.stringify(er) == JSON.stringify(er2)); // true

如果每个条目的属性顺序没有改变,它可以很好地工作json对象。

var er = [{name:"23222",id:"23"}, {id:"222",name:"23222222"}];var er2 = [{id:"23",name:"23222"}, {id:"222",name:"23222222"}];
var result = (JSON.stringify(er) == JSON.stringify(er2)); // false

但是数组的每个条目中只有一个属性或值,这将正常工作。

我想出了另一种方法。使用加入(")将它们更改为字符串,然后比较2个字符串:

var a1_str = a1.join(''),a2_str = a2.join('');
if (a2_str === a1_str) {}

我会这样做:

[2,3,4,5] == [2,3,4,5].toString()

当您使用“==”运算符时,javascript检查值(左和右)是否是相同的类型,如果是不同的javascript尝试将两边转换为相同的类型。

Array == String

数组有toString方法,所以javascript使用它将它们转换为相同的类型,以同样的方式编写:

[2,3,4,5].toString() == [2,3,4,5].toString()

另一种代码很少的方法(使用数组缩减数组包括):

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)
  • length检查确保一个数组中的元素集不仅仅是另一个数组的子集。

  • 减速机用于遍历一个数组并搜索另一个数组中的每个项目。如果找不到一个项目,则duce函数返回false

    1. 在第一个例子中,它正在测试是否包含一个元素
    2. 第二个例子也检查订单

虽然这个问题的最佳答案是正确和良好的,但提供的代码可能需要一些改进。

下面是我自己比较数组和对象的代码。代码简短明了:

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 objectsreturn equal && (valueType === "object" ? value.equals(otherValue) : value === otherValue);}, true);}Object.defineProperty(Object.prototype, "equals", {enumerable: false});

此代码支持嵌套在对象中的数组和嵌套在数组中的对象。

您可以在这个repl上查看全套测试并自己测试代码:https://repl.it/Esfz/3

如果它们只是两个数字或字符串数组,这是一个快速的单行数组

const array1 = [1, 2, 3];const array2 = [1, 3, 4];console.log(array1.join(',') === array2.join(',')) //false
const array3 = [1, 2, 3];const array4 = [1, 2, 3];console.log(array3.join(',') === array4.join(',')) //true

根据原问题的精神:

我想比较两个数组…理想情况下,有效没有如果它们相同,则为true,如果不相同,则为false。

我一直在对这里提出的一些更简单的建议进行性能测试,如下结果(从快到慢):

(67%) Tim Down

var i = a1.length;while (i--) {if (a1[i] !== a2[i]) return false;}return true

(69%) by user2782196

a1.every((v,i)=> v === a2[i]);

减少(74%)由DEIs

a1.reduce((a, b) => a && a2.includes(b), true);

加入&toString Gaizka Allende&vivek

a1.join('') === a2.join('');
a1.toString() === a2.toString();

一半toString(90%)作者:Victor Palomo

a1 == a2.toString();

stringify(100%)由radtek

JSON.stringify(a1) === JSON.stringify(a2);

说明下面的示例假设数组是排序的,单维数组。.length比较已被删除用于公共基准测试(将a1.length === a2.length添加到任何建议中,您将获得约10%的性能提升)。选择最适合您的解决方案,了解每个解决方案的速度和限制。

这比较了2个未排序的数组:

function areEqual(a, b) {if ( a.length != b.length) {return false;}return a.filter(function(i) {return !b.includes(i);}).length === 0;}
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)

尝试深度相等,它奏效了

var eq = require('deep-equal');eq({a: 1, b: 2, c: [3, 4]}, {c: [3, 4], a: 1, b: 2});

尽管这有很多答案,但我相信有一个是有帮助的:

const newArray = [ ...new Set( [...arr1, ...arr2] ) ]

问题中没有说明数组的结构将是什么样子,所以如果你确定你在数组中不会有嵌套数组或对象(它发生在我身上,这就是我得到这个答案的原因),上面的代码将起作用。

发生的事情是,我们使用扩展运算符(…)来合并两个数组,然后我们使用Set来消除任何重复项。一旦你有了它,你就可以比较它们的大小,如果所有三个数组的大小都相同,你就可以了。

这个答案也是0,正如我所说,确切的情况发生在我身上,所以也许有同样情况的人可能会在这里结束(就像我一样)。


编辑1.

回答Dmitry Grinko的问题:“为什么你在这里使用传播运算符(…)-… new Set?它不起作用”

考虑这段代码:

const arr1 = [ 'a', 'b' ]const arr2 = [ 'a', 'b', 'c' ]const newArray = [ new Set( [...arr1, ...arr2] ) ]console.log(newArray)

你会得到

[ Set { 'a', 'b', 'c' } ]

为了使用该值,您需要使用一些Set属性(请参阅https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set)。另一方面,当您使用此代码时:

const arr1 = [ 'a', 'b' ]const arr2 = [ 'a', 'b', 'c' ]const newArray = [ ...new Set( [...arr1, ...arr2] ) ]console.log(newArray)

你会得到

[ 'a', 'b', 'c' ]

这就是区别,前者会给我一个Set,它也可以工作,因为我可以得到该Set的大小,但后者给了我我需要的数组,更直接的是分辨率。

一个简单的方法:

function equals(a, b) {if ((a && !b) || (!a && b) || (!a && !b) || (a.length !== b.length)) {return false;}
var isDifferent = a.some(function (element, index) {return element !== b[index];});
return !isDifferent;}
JSON.stringify(collectionNames).includes(JSON.stringify(sourceNames)) ?  array.push(collection[i]) : null

我就是这么做的。

带有比较订单或不比较订单的选项:

function arraysEqual(a1, a2, compareOrder) {if (a1.length !== a2.length) {return false;}
return a1.every(function(value, index) {if (compareOrder) {return value === a2[index];} else {return a2.indexOf(value) > -1;}});}

已经有一些很好的答案了。但我想分享另一个在比较数组方面被证明是可靠的想法。我们可以使用JSON.stringify()比较两个数组。它将从数组中创建一个字符串,从而比较从两个数组中获得的两个字符串是否相等

JSON.stringify([1,{a:1},2]) == JSON.stringify([1,{a:1},2]) //true
JSON.stringify([1,{a:1},2]) == JSON.stringify([1,{a:2},2]) //false
JSON.stringify([1,{a:1},2]) == JSON.stringify([1,{a:2},[3,4],2]) //false
JSON.stringify([1,{a:1},[3,4],2]) == JSON.stringify([1,{a:2},[3,4],2]) //false
JSON.stringify([1,{a:2},[3,4],2]) == JSON.stringify([1,{a:2},[3,4],2]) //true
JSON.stringify([1,{a:2},[3,4],2]) == JSON.stringify([1,{a:2},[3,4,[5]],2]) //false
JSON.stringify([1,{a:2},[3,4,[4]],2]) == JSON.stringify([1,{a:2},[3,4,[5]],2]) //false
JSON.stringify([1,{a:2},[3,4,[5]],2]) == JSON.stringify([1,{a:2},[3,4,[5]],2]) //true

递归&适用于嵌套数组:

function ArrEQ(a1,a2){return(//:Are both elements arrays?Array.isArray(a1)&&Array.isArray(a2)?//:Yes: Test each entry for equality:a1.every((v,i)=>(ArrEQ(v,a2[i])))://:No: Simple Comparison:(a1===a2));;};;
console.log( "Works With Nested Arrays:" );console.log( ArrEQ([1,2,3,[4,5,[6,"SAME/IDENTICAL"]]],[1,2,3,[4,5,[6,"SAME/IDENTICAL"]]]));;console.log( ArrEQ([1,2,3,[4,5,[6,"DIFFERENT:APPLES" ]]],[1,2,3,[4,5,[6,"DIFFERENT:ORANGES"]]]));;

适用于多个参数和嵌套数组:

//:Return true if all of the arrays equal.//:Works with nested arrays.function AllArrEQ(...arrays){for(var i = 0; i < (arrays.length-1); i++ ){var a1 = arrays[i+0];var a2 = arrays[i+1];var res =(//:Are both elements arrays?Array.isArray(a1)&&Array.isArray(a2)?//:Yes: Compare Each Sub-Array://:v==a1[i]a1.every((v,i)=>(AllArrEQ(v,a2[i])))://:No: Simple Comparison:(a1===a2));;if(!res){return false;}};;return( true );};;
console.log( AllArrEQ([1,2,3,[4,5,[6,"ALL_EQUAL"   ]]],[1,2,3,[4,5,[6,"ALL_EQUAL"   ]]],[1,2,3,[4,5,[6,"ALL_EQUAL"   ]]],[1,2,3,[4,5,[6,"ALL_EQUAL"   ]]],));;

以下是TypeScript版本:

//https://stackoverflow.com/a/16436975/2589276export function arraysEqual<T>(a: Array<T>, b: Array<T>): boolean {if (a === b) return trueif (a == null || b == null) return falseif (a.length != b.length) return false
for (var i = 0; i < a.length; ++i) {if (a[i] !== b[i]) return false}return true}
//https://stackoverflow.com/a/16436975/2589276export function arraysDeepEqual<T>(a: Array<T>, b: Array<T>): boolean {return JSON.stringify(a) === JSON.stringify(b)}

摩卡的一些测试用例:

it('arraysEqual', function () {let a = [1,2]let b = [1,2]let c = [2,3]let d = [2, 3]let e = ['car','apple','banana']let f = ['car','apple','banana']let g = ['car','apple','banan8']
expect(arraysEqual(a, b)).to.equal(true)expect(arraysEqual(c, d)).to.equal(true)expect(arraysEqual(a, d)).to.equal(false)expect(arraysEqual(e, f)).to.equal(true)expect(arraysEqual(f, g)).to.equal(false)})
it('arraysDeepEqual', function () {let a = [1,2]let b = [1,2]let c = [2,3]let d = [2, 3]let e = ['car','apple','banana']let f = ['car','apple','banana']let g = ['car','apple','banan8']let h = [[1,2],'apple','banan8']let i = [[1,2],'apple','banan8']let j = [[1,3],'apple','banan8']
expect(arraysDeepEqual(a, b)).to.equal(true)expect(arraysDeepEqual(c, d)).to.equal(true)expect(arraysDeepEqual(a, d)).to.equal(false)expect(arraysDeepEqual(e, f)).to.equal(true)expect(arraysDeepEqual(f, g)).to.equal(false)expect(arraysDeepEqual(h, i)).to.equal(true)expect(arraysDeepEqual(h, j)).to.equal(false)})

使用数字/字符串/数组/对象的Récursive cmp函数

<script>var cmp = function(element, target){
if(typeof element !== typeof target){return false;}else if(typeof element === "object" && (!target || !element)){return target === element;}else if(typeof element === "object"){var keys_element = Object.keys(element);var keys_target  = Object.keys(target);       
if(keys_element.length !== keys_target.length){return false;}else{for(var i = 0; i < keys_element.length; i++){if(keys_element[i] !== keys_target[i])return false;if(!cmp(element[keys_element[i]], target[keys_target[i]]))return false;}return true;}}else{return element === target;
}};
console.log(cmp({key1: 3,key2: "string",key3: [4, "45", {key4: [5, "6", false, null, {v:1}]}]}, {key1: 3,key2: "string",key3: [4, "45", {key4: [5, "6", false, null, {v:1}]}]})); // true
console.log(cmp({key1: 3,key2: "string",key3: [4, "45", {key4: [5, "6", false, null, {v:1}]}]}, {key1: 3,key2: "string",key3: [4, "45", {key4: [5, "6", undefined, null, {v:1}]}]})); // false</script>

实际上,在Lodash留档中,他们给出了两个非常好的例子来比较和返回新数组的差异和相似性(分别在下面的例子中):

import { differenceWith, intersectionWith, isEqual } from 'lodash'
differenceWith([{ a: 1 }, { b: 1 }],[{ a: 1 }, { b: 1 }, { c: 1 }],isEqual) // []... 💀the bigger array needs to go first!
differenceWith([{ a: 1 }, { b: 1 }, { c: 1 }],[{ a: 1 }, { b: 1 }],isEqual,) // [{ c: 1 }] 🎉
intersectionWith([{ a: 1 }, { b: 1 }],[{ a: 1 }, { b: 1 }, { c: 1 }],isEqual,) // [{ a: 1 }, { b: 1 }] 🎉this one doesn't care about which is bigger

如果你不知道哪个数组会更大,你可以像这样为它写一个辅助函数:

const biggerFirst = (arr1, arr2) => {return arr1.length > arr2.length ? [arr1, arr2] : [arr2, arr1]}
const [big, small] = biggerFirst([{ a: 1 }, { b: 1 }],[{ a: 1 }, { b: 1 }, { c: 1 }],)
differenceWith(big, small, isEqual) // 🎉even though we have no idea which is bigger when they are fed to biggerFirst()

据我所知,这些也非常匹配,所以这很好。

我知道一切都依赖库不应该受到称赞,但这是我发现的一个非常常见的问题的最简洁/干净的解决方案。希望它能帮助到某人!

当两个数组具有相同的元素但顺序不同时,您的代码将无法正确处理这种情况。

看看我的代码和您的示例,它比较了两个元素为数字的数组,您可以修改或扩展它以用于其他元素类型(通过使用. join()而不是. toString())。

var a1 = [1,2,3];var a2 = [1,2,3];const arraysAreEqual = a1.sort().toString()==a2.sort().toString();// true if both arrays have same elements else falseconsole.log(arraysAreEqual);

In a simple way uning stringify but at same time thinking in complex arrays:
**Simple arrays**:var a = [1,2,3,4];var b = [4,2,1,4];JSON.stringify(a.sort()) === JSON.stringify(b.sort()) // true
**Complex arrays**:var a = [{id:5,name:'as'},{id:2,name:'bes'}];var b = [{id:2,name:'bes'},{id:5,name:'as'}];JSON.stringify(a.sort(function(a,b) {return a.id - b.id})) === JSON.stringify(b.sort(function(a,b) {return a.id - b.id})) // true
**Or we can create a sort function**
function sortX(a,b) {return a.id -b.id; //change for the necessary rules}JSON.stringify(a.sort(sortX)) === JSON.stringify(b.sort(sortX)) // true

我相信简单的JSECMAScript 2015,这是甜蜜和简单的理解。

var is_arrays_compare_similar = function (array1, array2) {
let flag = true;
if (array1.length == array2.length) {
// check first array1 object is available in array2 indexarray1.every( array_obj => {if (flag) {if (!array2.includes(array_obj)) {flag = false;}}});        
// then vice versa check array2 object is available in array1 indexarray2.every( array_obj => {if (flag) {if (!array1.includes(array_obj)) {flag = false;}}});
return flag;} else {return false;}    
}

我知道处理大型数据集时JSON.stringfy很慢,但是如果你使用模板文字呢?

示例:

const a = [1, 2, 3];const b = [1, 2, 'test'];
const a_string = Array.isArray(a) && `${a}`;const b_string = Array.isArray(b) && `${b}`;
const result = (a === b);
console.log(result);

当然,考虑到你正在使用ES6。

=)

最短

对于数字数组,请尝试:

a1==''+a2

var a1 = [1,2,3];var a2 = [1,2,3];
console.log( a1==''+a2 )

备注:当数组也包含字符串时,此方法将不起作用,例如a2 = [1, "2,3"]

使用过滤器和箭头函数的替代方法

arrOne.length === arrTwo.length && arrOne.filter((currVal, idx) => currVal !== arrTwo[idx]).length === 0
let equals = (LHS, RHS) => {if (!(LHS instanceof Array)) return "false > L.H.S is't an array";if (!(RHS instanceof Array)) return "false > R.H.S is't an array";if (LHS.length != RHS.length) return false;let to_string = x => JSON.stringify(x.sort((a, b) => a - b));return to_string(LHS) == to_string(RHS);};
let l = console.logl(equals([5,3,2],[3,2,5]))    // truel(equals([3,2,5,3],[3,2,5]))  // false

这里有一种未排序数组和自定义比较的可能性:

    const array1 = [1,3,2,4,5];const array2 = [1,3,2,4,5];    
const isInArray1 = array1.every(item => array2.find(item2 => item===item2))const isInArray2 = array2.every(item => array1.find(item2 => item===item2))    
const isSameArray = array1.length === array2.length && isInArray1 && isInArray2    
console.log(isSameArray); //true

2020年引入了第一阶段提案,通过向语言添加Array.prototype.equals来允许轻松比较数组。这是它的工作方式,没有任何库、monkeypatch或任何其他代码:

[1, 2, 3].equals([1, 2, 3]) // evaluates to true[1, 2, undefined].equals([1, 2, 3]) // evaluates to false[1, [2, [3, 4]]].equals([1, [2, [3, 4]]]) // evaluates to true

到目前为止,这只是一个初步的建议——TC39现在将“花时间研究问题空间、解决方案和交叉关注点”。如果它进入第二阶段,它很有可能最终被整合到语言本身。

您可以简单地使用是否相等从Lodash库。它非常高效和干净。

import isEqual from "lodash/isEqual";
const isTwoArraysEqual = isEqual(array1, array2);

这种方法只适用于标量数组,就像这个问题的第二个投票答案一样。

var arrs = [[[1, 2, 3], [1, 2, 3]], // true[[1, 2, 3, 4], [1, 2, 3]], // false[[1, 2, 3], [1, 2, 3, 4]], // false]
const arraysEqual = (one, two) => (one.filter((i, n) => two[n] === i).length === one.length) && (two.filter((i, n) => one[n] === i).length === two.length)
arrs.forEach(arr => {console.log(arraysEqual(arr[0], arr[1]))})

没有ES6语法:

var arrs = [[[1, 2, 3], [1, 2, 3]], // true[[1, 2, 3, 4], [1, 2, 3]], // false[[1, 2, 3], [1, 2, 3, 4]], // false]
function arraysEqual(one, two) {return (one.filter((i, n) => two[n] === i).length === one.length) && (two.filter((i, n) => one[n] === i).length === two.length)}
arrs.forEach(arr => {console.log(arraysEqual(arr[0], arr[1]))})

如果您正在编写测试代码,则

import chai from 'chai';const arr1 = [2, 1];const arr2 = [2, 1];chai.expect(arr1).to.eql(arr2); // Will pass. `eql` is data compare instead of object compare.

这是一个棘手的隐式数组相等性检查,但可以在相干数组到字符串之后立即处理这项工作。

var a1 = [1, 2, 3];var a2 = [1, 2, 3];var isEqual = a1 <= a2 && a1 >= a2; // true

我在https://stackoverflow.com/a/10316616/711085回答了这个问题(此后被标记为这个答案的副本)。


对于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 === equalityreturn false;return true;}

在一些罕见的情况下,如果业务逻辑继续附加到数组的末尾,还可以通过检查if (a.length>0 && a[a.length-1]!==b[b.length-1]) return false;来实现平均情况O(1)和最坏情况O(N)。

简单

type Values = number | string;
/** Not sorted array */function compare<Values>(a1: Array<Values>, a2: Array<Values>): boolean {if (a1.length !== a2.length) {return false;}
/** Unique values */const set1 = new Set<Values>(a1);const set2 = new Set<Values>(a2);if (set1.size !== set2.size) {return false;}
return [...set1].every((value) => [...set2].includes(value));}
compare([1, 2, 3], [1, 2, 3]);    // truecompare([1, 2, 3], [1, 3, 2]);    // truecompare([1, 1, 1], [1, 2, 3]);    // falsecompare([1, 1, 2, 3], [1, 2, 3]); // false
/** Sorted arrays, faster method */function compareSorted<Values>(a1: Array<Values>, a2: Array<Values>): boolean {if (a1.length !== a2.length) {return false;}
/** Unique values */const set1 = new Set<Values>(a1);const set2 = new Set<Values>(a2);if (set1.size !== set2.size) {return false;}
return [...set1].every((value, index) => value === [...set2][index]);}
compareSorted([1, 2, 3], [1, 2, 3]);    // truecompareSorted([1, 2, 3], [1, 3, 2]);    // falsecompareSorted([1, 1, 1], [1, 2, 3]);    // falsecompareSorted([1, 1, 2, 3], [1, 2, 3]); // false

代码高尔夫

有很多答案展示了如何有效地比较数组。

下面是最短比较两个int或(string)数组的方法,以代码字节为单位。

const a = [1, 2, 3]const b = [1, 2, 3]
console.log("1. ", a.join() == b.join())console.log("2. ", a.join() == [].join())
console.log("3. ", 1 + a == 1 + b)console.log("4. ", 1 + [] == 1 + b)
// even shorterconsole.log("4. b) ", a == "" + b)
// false positives (see flaws)console.log("5. ", 1 + ["3"] == 1 + [3]) // type differencesconsole.log("6. ", 1 + ["1,2"] == 1 + ["1", "2"])

补充说明

这是有效的,因为当使用+运算符时,类型会自动转换为允许连接。在这种情况下,1[1, 2, 3]都转换为字符串。

在内部,JavaScript使用[1, 2, 3].join()将数组转换为字符串,然后将它们添加到结果11,2,3中。在两个数组上执行此操作时,可以简单地使用=====来比较两个字符串。

缺陷

使用这种技术,比较不关心要比较的数组中的元素是否属于不同类型。由于字符串转换,[1, 2]将等于["1", "2"]

编辑:正如评论中指出的,比较字符串数组可能会产生误报,例如["1,2"]等于["1", "2"]。如果您确定这些永远不会发生(例如在许多代码高尔夫球挑战中),则无需担心。

免责声明

虽然这对代码高尔夫很有用,但它可能不应该在生产代码中使用。指出的两个缺陷也没有帮助。

所有其他的解决方案看起来都很复杂。这可能不是处理所有边缘情况的最有效方法,但对我来说效果很好。

Array.prototype.includesArray = function(arr) {return this.map(i => JSON.stringify(i)).includes(JSON.stringify(arr))}

用法

[[1,1]].includesArray([1,1])// true
[[1,1]].includesArray([1,1,2])// false

令人惊讶的是,没有人提出解决方案#0

const a = [1, 2, 3]const b = [1, 2, 3, 4]a.find((v,i) => v !== b[i])

这里的好处是,它不会比较所有值,而是寻找第一个出现的值并尽早结束循环。或者换句话说,它不会问“两个数组相等吗?”它会问“一个数组不同与另一个数组不同吗?”。

性能基准排名第三https://jsben.ch/TgFrA

请记住,顺序很重要,a.find(...) !== b.find(...)可以由a.length === b.length检查

if (a.length === b.length && a.find((v,i) => v !== b[i]) === undefined) {// equal}

给你,

const a = [1, 2, 3]const b = [1, 2, 3, 4, 5]
const diff = b.filter(e => !a.includes(e))console.log(diff)

上面的大多数答案都不适用于无序列表。这也适用于无序列表。

const a = [3, 2, 1]const b = [1, 2, 3, 4, 5]
const diff = b.filter(e => !a.includes(e))console.log(diff)

如果a的大小大于b,

const a = [1, 2, 3, 4, 5]const b = [3, 2, 1]
const diff = a.length > b.length ? a.filter(e => !b.includes(e)) : b.filter(e => !a.includes(e))console.log(diff)

这里有许多复杂的长答案,所以我只想贡献一个非常简单的答案:使用toString()将数组转换为简单的逗号分隔字符串,您可以轻松地与===进行比较

let a = [1, 2, 3]let b = [1, 2, 3]let c = [4, 2, 3]
console.log(a.toString())  // this outputs "1,2,3"console.log(a.toString() === b.toString())  // this outputs true because "1,2,3" === "1,2,3"console.log(a.toString() === c.toString())  // this outputs false because "1,2,3" != "4,2,3"

这里有很多好答案。这是我通常做的-

if ( arr1.length === arr2.length && arr1.every((a1) => arr2.includes(a1)) ) {// logic}

只有当所有元素都通过给定的Camparison时,every()才会返回true逻辑。如果它遇到false,在任何迭代中,它都会终止并返回false。

时间复杂度为O(n*m)。