How to compare arrays in JavaScript?
我想比较两个数组…理想的,高效的。没什么好奇心,如果相同的话,只有
1 2 3 4 | 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编码每个数组,但是有没有一种更快或更好的方法可以简单地比较数组而不必迭代每个值?
要比较数组,请循环它们并比较每个值:
比较数组:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | // 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 | [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; |
你可能会说"但是比较字符串要快得多-没有循环…",那么你应该注意到有循环。第一个递归循环将数组转换为字符串,第二个循环比较两个字符串。所以这个方法比使用字符串更快。
我认为大量的数据应该总是存储在数组中,而不是存储在对象中。但是,如果使用对象,也可以对它们进行部分比较。方法如下:
比较对象:我在上面说过,两个对象实例永远不会相等,即使它们现在包含相同的数据:
1 | ({a:1, foo:"bar", numberOfTheBeast: 666}) == ({a:1, foo:"bar", numberOfTheBeast: 666}) //false |
这是有原因的,因为对象中可能存在私有变量。
但是,如果您只是使用对象结构来包含数据,那么比较仍然是可能的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | 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的数据,而不是类实例和其他东西。如果你想比较更复杂的物体,看看这个答案,它的超长函数。要使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | ... // 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]) { ... |
我为这两个功能做了一个小测试工具。
附加:带有Samy Bencherif为您在嵌套数组中搜索特定对象的情况准备了有用的函数,可从以下位置获得:https://jsfiddle.net/samy bencherif/8352y6yww/
虽然这只适用于标量数组(请参见下面的注释),但它很短:
1 | array1.length === array2.length && array1.every(function(value, index) { return value === array2[index]}) |
rr,在ecmascript 6/coffeescript/typescript中,带有箭头函数:
1 | array1.length === array2.length && array1.every((value, index) => value === array2[index]) |
(注:"scalar"在这里表示可以直接使用
更新
根据我从评论中读到的内容,对数组进行排序和比较可能会得到准确的结果:
1 | array1.length === array2.length && array1.sort().every(function(value, index) { return value === array2.sort()[index]}); |
如:
1 2 | array1 = [2,3,1,4]; array2 = [1,2,3,4]; |
那么上述代码将给出
我喜欢将下划线库用于数组/对象重编码项目…在下划线和lodash中,无论您是在比较数组还是对象,它都是这样的:
1 2 | _.isEqual(array1, array2) // returns a boolean _.isEqual(object1, object2) // returns a boolean |
- 下划线IsEqual文档
- Lodash等质量文件
我认为这是使用JSON Stringify进行此操作的最简单方法,在某些情况下,它可能是最佳解决方案:
1 | JSON.stringify(a1) === JSON.stringify(a2); |
这会将对象
请注意,您不再比较对象,而是比较对象的字符串表示形式。这可能不是你想要的。
不清楚你所说的"相同"是什么意思。例如,下面的数组
1 | var a = ["foo", ["bar"]], b = ["foo", ["bar"]]; |
这里有一个优化的数组比较函数,它使用严格的相等性依次比较每个数组的相应元素,并且不对本身是数组的数组元素进行递归比较,这意味着对于上面的示例,
1 2 3 4 5 6 7 8 | 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; }; |
实用的方法
我认为说一个特定的实现是"正确的方式"是错误的。如果它只是"正确的"("正确的"),而不是"错误的"解决方案。汤姆?与基于字符串的数组比较相比,S解决方案有了明显的改进,但这并不意味着它在客观上是"正确的"。什么是正确的?是最快的吗?它是最灵活的吗?这是最容易理解的吗?它是调试最快的吗?它是否使用最少的操作?有什么副作用吗?没有一个解决方案能做到最好。好的。
汤姆?S可以说他的解决方案很快,但我也会说这是不必要的复杂。它试图成为一个适用于所有数组的一体式解决方案,无论是否嵌套。实际上,它甚至接受的不仅仅是数组作为输入,而且仍然试图给出一个"有效"的答案。好的。仿制药提供可重用性
我的答案将以不同的方式处理这个问题。我将从一个只涉及遍历数组的通用
1 2 3 4 5 | // arrayCompare :: (a -> a -> Bool) -> [a] -> [a] -> Bool const arrayCompare = f => ([x,...xs]) => ([y,...ys]) => x === undefined && y === undefined ? true : Boolean (f (x) (y)) && arrayCompare (f) (xs) (ys) |
在我看来,最好的代码甚至不需要注释,这也不例外。这里很少发生这样的事情,你几乎不费吹灰之力就能理解这个过程的行为。当然,现在有些ES6语法对您来说可能是陌生的,但这仅仅是因为ES6相对较新。好的。
如类型所示,
接下来,使用我们的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // equal :: a -> a -> Bool const equal = x => y => x === y // notice: triple equal // arrayEqual :: [a] -> [a] -> Bool const 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 |
就这么简单。
注意,我们还将
我们可以用
1 2 3 4 5 6 7 8 9 10 11 12 | // looseEqual :: a -> a -> Bool const looseEqual = x => y => x == y // notice: double equal // arrayLooseEqual :: [a] -> [a] -> Bool const 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 |
深度比较(递归)
你可能已经注意到这只是一个肤浅的比较。汤姆肯定是?"S解决方案是"正确的方式?"因为它做了隐含的深层比较,对吗?好的。
好吧,我们的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | // isArray :: a -> Bool const isArray = Array.isArray // arrayDeepCompare :: (a -> a -> Bool) -> [a] -> [a] -> Bool const 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 |
就这么简单。我们使用另一个高阶函数建立了一个深度比较器。这次,我们使用一个自定义的比较器包装
因为
1 2 3 4 5 6 7 | // arrayDeepEqual :: [a] -> [a] -> Bool const arrayDeepEqual = arrayDeepCompare (equal) // arrayDeepLooseEqual :: [a] -> [a] -> Bool const arrayDeepLooseEqual = arrayDeepCompare (looseEqual) |
对我来说,这已经是比汤姆明显的进步了?因为我可以根据需要为数组显式地选择浅比较或深比较。好的。对象比较(示例)
现在,如果您有一个对象数组或其他东西呢?如果每个对象都具有相同的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // idEqual :: {id: Number} -> {id: Number} -> Bool const idEqual = x => y => x.id !== undefined && x.id === y.id // arrayIdEqual :: [a] -> [a] -> Bool const 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 |
就这么简单。这里我使用了普通的JS对象,但是这种类型的比较器可以用于任何对象类型,甚至是您的自定义对象。汤姆?为了支持这种平等测试,需要对S解决方案进行彻底修改。好的。
有物体的深阵列?不是问题。我们构建了高度通用的通用函数,因此它们可以在各种各样的用例中工作。好的。
1 2 3 4 | const xs = [{id:1}, [{id:2}]] const ys = [{id:1}, [{id:2}]] console.log (arrayCompare (idEqual) (xs) (ys)) //=> false console.log (arrayDeepCompare (idEqual) (xs) (ys)) //=> true |
任意比较(示例)
或者,如果你想做另一种完全武断的比较呢?也许我想知道每个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // gt :: Number -> Number -> Bool const gt = x => y => x > y // arrayGt :: [a] -> [a] -> Bool const 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 |
少即是多
你可以看到我们实际上用更少的代码做的更多。
我们可以很容易地定义两个数组的具体比较方式:浅、深、严格、松散、某些对象属性或任意计算,或这些属性的任何组合,所有这些都使用一个过程,即
是最快的吗?不。但可能也不需要。如果速度是衡量代码质量的唯一标准,那么很多非常好的代码都会被丢弃,这就是为什么我将这种方法称为实用的方法。或者更公平一点,一种实用的方法。这个描述适用于这个答案,因为我并不是说这个答案与其他答案相比只是实用的;它客观上是真实的。我们已经获得了很高的实用性,代码很少,很容易解释。没有其他代码可以说我们没有获得这个描述。好的。
这是否使它成为您的"正确"解决方案?这由你决定。没有人能为你做这些,只有你知道你的需要。在几乎所有情况下,我都看重简单、实用和通用的代码,而不是聪明和快速的代码。你的价值可能会有所不同,所以选择适合你的。好的。编辑
我以前的回答更侧重于将
本着原始问题的精神:
I'd like to compare two arrays... ideally, efficiently. Nothing
fancy, just true if they are identical, and false if not.
我一直在对这里提出的一些更简单的建议进行性能测试,结果如下(从快到慢):
而(67%)由蒂姆下降
1 2 3 4 5 | var i = a1.length; while (i--) { if (a1[i] !== a2[i]) return false; } return true |
每(69%)用户2782196
1 | a1.every((v,i)=> v === a2[i]); |
通过DEIS减少(74%)。
1 | a1.reduce((a, b) => a && a2.includes(b), true); |
由Gaizka Allende和Vivek加入&toString(78%)。
1 2 3 | a1.join('') === a2.join(''); a1.toString() === a2.toString(); |
维克托·帕洛莫(Victor Palomo)的半音(90%)。
1 | a1 == a2.toString(); |
由Radtek将(100%)架线
1 | JSON.stringify(a1) === JSON.stringify(a2); |
Note the examples below assumes the arrays are sorted, single-dimensional arrays.
.length comparison has been removed for a common benchmark (adda1.length === a2.length to any of the suggestions and you will get a ~10% performance boost). Choose whatever solutions that works best for you knowing the speed and limitation of each.Unrelated note: it is interesting to see people getting all trigger-happy John Waynes on the down vote button on perfectly legitimate answers to this question.
以汤姆为中心?扎托的回答是,我同意只迭代数组是最快的。另外(像其他人已经说过的那样),函数应该被调用为equals/equal,而不是compare。有鉴于此,我修改了函数来处理比较数组的相似性——也就是说,它们有相同的元素,但顺序不对——以供个人使用,我想我会把它放在这里让大家看。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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的附加严格参数。这个严格的参数定义数组是否需要在内容和内容顺序上完全相等,或者只包含相同的内容。
例子:
1 2 3 4 5 6 7 8 9 10 11 | var arr1 = [1, 2, 3, 4]; var arr2 = [2, 1, 4, 3]; // Loosely equal to 1 var arr3 = [2, 2, 3, 4]; // Not equal to 1 var arr4 = [1, 2, 3, 4]; // Strictly equal to 1 arr1.equals(arr2); // false arr1.equals(arr2, false); // true arr1.equals(arr3); // false arr1.equals(arr3, false); // false arr1.equals(arr4); // true arr1.equals(arr4, false); // true |
我还编写了一个关于函数的快速jsiddle,这个示例:
http://jsfiddle.net/roundaround/dlkxx/
尽管这有很多答案,但我相信这是一个有帮助的答案:
1 | const newArray = [ ...new Set( [...arr1, ...arr2] ) ] |
这个问题中没有说明数组的结构将是怎样的,所以如果你确定你不会在数组中有嵌套的数组或对象(发生在我身上,这就是我得出这个答案的原因),上面的代码就可以工作了。
我们使用了扩散算子(…)若要合并两个数组,则使用set来消除任何重复项。一旦你有了它们,你就可以比较它们的大小了,如果这三个数组的大小都相同,你就可以开始了。
这个答案也忽略了元素的顺序,正如我所说,确切的情况发生在我身上,所以可能相同情况下的某个人最终会出现在这里(正如我所做的)。
编辑一。
回答德米特里·格林科的问题:"你为什么要用扩频器(……)这里——新的一套?它不起作用"
考虑此代码:
1 2 3 4 | const arr1 = [ 'a', 'b' ] const arr2 = [ 'a', 'b', 'c' ] const newArray = [ new Set( [...arr1, ...arr2] ) ] console.log(newArray) |
你会得到
1 | [ Set { 'a', 'b', 'c' } ] |
为了使用该值,您需要使用一些集合属性(请参见https://developer.mozilla.org/en-us/docs/web/javascript/reference/global_-objects/set)。另一方面,当您使用此代码时:
1 2 3 4 | const arr1 = [ 'a', 'b' ] const arr2 = [ 'a', 'b', 'c' ] const newArray = [ ...new Set( [...arr1, ...arr2] ) ] console.log(newArray) |
你会得到
1 | [ 'a', 'b', 'c' ] |
这就是区别,前者会给我一个集合,它也会起作用,因为我可以得到这个集合的大小,但后者会给我需要的数组,这更直接地决定了分辨率。
与json.encode在同一行上使用join()。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | function checkArrays( arrA, arrB ){ //check if lengths are different if(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 compare var 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) ); //true console.log( checkArrays(a,c) ); //false console.log( checkArrays(a,d) ); //false console.log( checkArrays(a,e) ); //true |
唯一的问题是,如果您关心最后一个比较测试的类型。如果您关心类型,则必须循环。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | function checkArrays( arrA, arrB ){ //check if lengths are different if(arrA.length !== arrB.length) return false; //slice so we do not effect the orginal //sort makes sure they are in order var 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) ); //true console.log( checkArrays(a,c) ); //false console.log( checkArrays(a,d) ); //false console.log( checkArrays(a,e) ); //false |
如果顺序应该保持不变,而不仅仅是循环,则不需要排序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | function checkArrays( arrA, arrB ){ //check if lengths are different if(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) ); //true console.log( checkArrays(a,b) ); //false console.log( checkArrays(a,c) ); //false console.log( checkArrays(a,d) ); //false console.log( checkArrays(a,e) ); //false |
如果它们只是两个数字或字符串数组,这是一个快速的单行
1 2 3 4 5 6 7 | 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 |
如果您使用的是像mocha和chai断言库这样的测试框架,那么可以使用深度相等来比较数组。
1 | expect(a1).to.deep.equal(a2) |
只有当数组在相应的索引处具有相等的元素时,才会返回true。
对于一维数组,您可以简单地使用:
这还将处理索引不匹配的数组。
这里是一个类型脚本版本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //https://stackoverflow.com/a/16436975/2589276 export function arraysEqual<T>(a: Array<T>, b: Array<T>): boolean { if (a === b) return true if (a == null || b == null) return false if (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/2589276 export function arraysDeepEqual<T>(a: Array<T>, b: Array<T>): boolean { return JSON.stringify(a) === JSON.stringify(b) } |
Mocha的一些测试案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 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) }) |
我们可以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | function compareArrays(array1, array2) { if (array1.length === array2.length) return array1.every((a, index) => a === array2[index]) else return false } // test var 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)) // true console.log(compareArrays(a1,a3)) // false console.log(compareArrays(a3,a4)) // false |
我的解决方案是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /** * 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; } else if (x[p] !== y[p]) return false; } } else return x === y; return true; }; |
使用任何嵌套的数据结构,显然会忽略对象的方法。甚至不要考虑用这个方法扩展object.prototype,当我尝试过一次时,jquery中断了;)
对于大多数数组,它仍然比大多数序列化解决方案更快。对于对象记录数组,它可能是最快的比较方法。
这将比较两个未排序的数组:
1 2 3 4 5 6 7 8 | function areEqual(a, b) { if ( a.length != b.length) { return false; } return a.filter(function(i) { return !b.includes(i); }).length === 0; } |
延伸汤姆?扎托思想。tomas的array.prototype.compare应被称为array.prototype.compareIdentical。
它过去了:
1 2 3 4 | [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 | [[1, 2, [3, 2]],1, 2, [3, 2]].compareIdentical([1, 2, [3, 2],[1, 2, [3, 2]]]) |
以下是更好的版本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | Array.prototype.compare = 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; this.sort(); array.sort(); for (var i = 0; i < this.length; i++) { // Check if we have nested arrays if (this[i] instanceof Array && array[i] instanceof Array) { // recurse into the nested arrays if (!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; } |
http://jsfidle.net/igos/bcfcy/
这是一条很短的路
1 2 3 4 | function arrEquals(arr1, arr2){ arr1.length == arr2.length && arr1.filter(elt=>arr2.includes(elt)).length == arr1.length } |
另一种代码很少的方法(使用array reduce和array include):
1 | arr1.length == arr2.length && arr1.reduce((a, b) => a && arr2.includes(b), true) |
如果还要比较顺序的相等性:
1 | arr1.length == arr2.length && arr1.reduce((a, b, i) => a && arr2[i], true) |
length 检查确保一个数组中的元素集不仅仅是另一个数组的子集。reducer用于遍历一个数组并搜索另一个数组中的每个项。如果找不到一个项,reduce函数返回
false 。- 在第一个示例中,正在测试是否包含元素
- 第二个示例也检查订单
递归处理嵌套数组(amp;W):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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"]]] ));; |
在我的例子中,比较数组只包含数字和字符串。此函数将显示数组是否包含相同的元素。
1 2 3 | function are_arrs_match(arr1, arr2){ return arr1.sort().toString() === arr2.sort().toString() } |
让我们来测试一下!
1 2 3 4 5 6 | arr1 = [1, 2, 3, 'nik'] arr2 = ['nik', 3, 1, 2] arr3 = [1, 2, 5] console.log (are_arrs_match(arr1, arr2)) //true console.log (are_arrs_match(arr1, arr3)) //false |
1 | JSON.stringify(collectionNames).includes(JSON.stringify(sourceNames)) ? array.push(collection[i]) : null |
我就是这样做的。
1 2 3 4 5 6 7 8 9 10 11 | 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); |
//////或///////
1 2 3 4 5 6 7 8 9 10 11 | 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) |
比较两个数组:
1 2 3 4 5 6 7 8 9 10 | var arr1 = [1,2,3]; var arr2 = [1,2,3]; function compare(arr1,arr2) { if((arr1 == arr2) && (arr1.length == arr2.length)) return true; else return false; } |
调用函数
1 | var isBool = compare(arr1.sort().join(),arr2.sort().join()); |
可选择是否比较订单:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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; } }); } |
与嵌套数组一起使用多个参数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | //: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" ]]], ));; |
此脚本比较对象、数组和多维数组
1 2 3 4 5 6 7 8 9 | 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; } |
第一行检查它是否是原始类型。如果是这样,它会比较这两个参数。
如果它们是对象。它迭代对象并递归检查每个元素。
用途:
1 2 3 | var a=[1,2,[1,2]]; var b=[1,2,[1,2]]; var isEqual=compare(a,b); //true |
已经有了一些很好的答案,但我想分享另一个在比较数组时被证明是可靠的想法。我们可以使用json.stringify()比较两个数组。它将在数组中创建一个字符串,从而比较从两个数组中获得的两个字符串是否相等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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 |
原因是,identity或strict运算符(==)与不进行类型转换相比,这意味着如果两个值没有相同的值和相同的类型,它们就不会被视为相等的。
看看这个链接,它让你毫无疑问了解身份操作员如何工作的简单方法
一个简单的方法:
1 2 3 4 5 6 7 8 9 10 11 | 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; } |
我使用了:连接数组并创建一个字符串进行比较。对于比本例复杂的场景,可以使用其他一些分隔符。
1 2 3 4 5 6 7 8 9 | var a1 = [1,2,3]; var a2 = [1,2,3]; if (a1.length !== a2.length) { console.log('a1 and a2 are not equal') }else if(a1.join(':') === a2.join(':')){ console.log('a1 and a2 are equal') }else{ console.log('a1 and a2 are not equal') } |
从[A]中选择每一个,并从[B]中遍历所有:结果:1, 5
1 2 3 4 5 6 7 8 9 10 | var a = [1,4,5,9]; var b = [1,6,7,5]; for (i = 0; i < a.length; i++) { for (z = 0; z < a.length; z++) { if (a[i] === b[z]) { console.log(b[z]); // if match > console.log it } } } |
此函数比较两个任意形状和尺寸的数组:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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; } |
虽然这个问题的最上面的答案是正确和良好的,但是提供的代码可能会有一些改进。
下面是我自己的用于比较数组和对象的代码。代码简短:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | 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上看到一整套测试并自己测试代码。
我的解决方案比较对象,而不是数组。这和汤姆一样有效吗?s as数组是对象,但没有警告:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | Object.prototype.compare_to = function(comparable){ // Is the value being compared an object if(comparable instanceof Object){ // Count the amount of properties in @comparable var count_of_comparable = 0; for(p in comparable) count_of_comparable++; // Loop through all the properties in @this for(property in this){ // Decrements once for every property in @this count_of_comparable--; // Prevents an infinite loop if(property !="compare_to"){ // Is the property in @comparable if(property in comparable){ // Is the property also an Object if(this[property] instanceof Object){ // Compare the properties if yes if(!(this[property].compare_to(comparable[property]))){ // Return false if the Object properties don't match return false; } // Are the values unequal } else if(this[property] !== comparable[property]){ // Return false if they are unequal return false; } } else { // Return false if the property is not in the object being compared return false; } } } } else { // Return false if the value is anything other than an object return false; } // Return true if their are as many properties in the comparable object as @this return count_of_comparable == 0; } |
希望这能帮助你或任何人寻找答案。
如果数组是普通的,并且顺序很重要,那么这两行可能有帮助
1 2 3 4 5 6 7 | //Assume var 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遍历数组中的一个元素,如果"a"的至少一个元素与"b"的元素不相等,则返回"false"把这个包起来就行了
以下是咖啡的描述版本,适合那些喜欢的人:
1 2 3 4 5 6 7 8 9 10 11 | Array.prototype.equals = (array) -> return false if not array # if the other array is a falsy value, return return 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 arrays if not item.equals(array[index]) # recurse into the nested arrays return false else if this[index] != array[index] return false # Warning - two different object instances will never be equal: {x:20} != {x:20} true |
所有学分归@tomas zato所有。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | function compareArrays(arrayA, arrayB) { if (arrayA.length != arrayB.length) return true; for (i = 0; i < arrayA.length; i++) if (arrayB.indexOf(arrayA[i]) == -1) { return true; } } for (i = 0; i < arrayB.length; i++) { if (arrayA.indexOf(arrayB[i]) == -1) { return true; } } return false; } |
试过深度均等,但效果很好
1 2 | var eq = require('deep-equal'); eq({a: 1, b: 2, c: [3, 4]}, {c: [3, 4], a: 1, b: 2}); |
此外,我已经根据需要将Thomas的解决方案转换为无订单比较。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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; } |
如果元素数量不匹配或其中一个元素不在另一个元素的数组中,则可以取消"相同性"的资格。这里有一个对我有用的简单函数。
1 2 3 4 5 6 7 8 9 | function isSame(arr1,arr2) { var same=true; for(var i=0;i < arr1.length;i++) { if(!~jQuery.inArray(arr1[i],arr2) || arr1.length!=arr2.length){ same=false; } } return same; } |
I came up with another way to do it. Use join('') to change them to string, and then compare 2 strings:
1 2 3 4 | var a1_str = a1.join(''), a2_str = a2.join(''); if (a2_str === a1_str) {} |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | function palindrome(text) { var Res1 = new Array(); var Res2 = new Array(); for (i = 0; i < text.length; i++) { Res1[i] = text.substr(i, 1); } j=0; for (k = (text.length-1); k>=0; k--) { Res2[j] = text.substr(k, 1); j=j+1; } if(JSON.stringify(Res1)==JSON.stringify(Res2)){ return true; }else{ return false; } } document.write(palindrome("katak")); |
我非常喜欢这种方法,因为它实际上比其他方法更简洁。它本质上是将所有项目与一个保持相同值的累加器进行对比,如果累加器达到一个不同的值,则用
1 2 3 | function areArrayItemsEqual(arr) { return !!(Math.abs(arr.reduce((a, b) => a === b ? b : NaN)) + 1); } |
仅适用于一级数组、字符串或数字类型
1 2 3 | function isArrayEqual(ar1, ar2) { return !ar1.some(item => ar2.indexOf(item) === -1) && ar1.length === ar2.length; } |
我想要这个:
1 | [2,3,4,5] == [2,3,4,5].toString() |
当使用"=="运算符时,javascript检查值(左和右)是否为同一类型,如果为不同的javascript,则尝试将两边转换为同一类型。
1 | Array == String |
数组具有ToString方法,因此JavaScript使用它将它们转换为相同的类型,使用相同的方式编写:
1 | [2,3,4,5].toString() == [2,3,4,5].toString() |
1 2 3 | var er = [{id:"23",name:"23222 <hr><P>到目前为止,我使用此代码没有问题:</P>[cc lang="javascript"]if(a.join() == b.join()) ... |
即使项目中有逗号,它也能工作。