How to check if two arrays are equal with JavaScript?
1 2 3 4 5 | var a = [1, 2, 3]; var b = [3, 2, 1]; var c = new Array(1, 2, 3); alert(a == b +"|" + b == c); |
演示
如何检查这些数组是否相等,如果相等,如何获取返回
jquery是否提供了这种方法?
这是你应该做的。请不要使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | function arraysEqual(a, b) { if (a === b) return true; if (a == null || b == null) return false; if (a.length != b.length) return false; // If you don't care about the order of the elements inside // the array, you should sort both arrays here. // Please note that calling sort on an array will modify that array. // you might want to clone your array first. for (var i = 0; i < a.length; ++i) { if (a[i] !== b[i]) return false; } return true; } |
选项1好的。
最简单的选择,几乎适用于所有情况,除了
1 2 3 4 | function arraysEqual(a1,a2) { /* WARNING: arrays must not contain {objects} or behavior may be undefined */ return JSON.stringify(a1)==JSON.stringify(a2); } |
(如果数组包含对象,这可能不起作用。这是否仍然适用于对象取决于JSON实现是否对键进行排序。例如,至少在chrome上,json.stringify函数倾向于按照定义的顺序返回键(至少我注意到了),但这种行为在任何时候都会发生变化,并且不应该依赖。.如果您选择不使用列表中的对象,这应该可以正常工作。如果列表中的对象都具有唯一的ID,则可以执行
这也适用于嵌套数组。好的。
但是,由于创建这些字符串和垃圾收集字符串的开销,它的效率稍低。好的。
选项2好的。
更多"正确"选项,您可以覆盖它来处理特殊情况(如常规对象、空/未定义对象和自定义对象,如果您愿意的话):好的。
1 2 3 4 5 6 7 8 9 10 11 | // generally useful functions function type(x) { // does not work in general, but works on JSONable objects we care about... modify as you see fit // e.g. type(/asdf/g) -->"[object RegExp]" return Object.prototype.toString.call(x); } function zip(arrays) { // e.g. zip([[1,2,3],[4,5,6]]) --> [[1,4],[2,5],[3,6]] return arrays[0].map(function(_,i){ return arrays.map(function(array){return array[i]}) }); } |
nbsp;好的。
1 2 3 4 5 6 7 8 9 10 11 12 | // helper functions function allCompareEqual(array) { // e.g. allCompareEqual([2,2,2,2]) --> true // does not work with nested arrays or objects return array.every(function(x){return x==array[0]}); } function isArray(x){ return type(x)==type([]) } function getLength(x){ return x.length } function allTrue(array){ return array.reduce(function(a,b){return a&&b},true) } // e.g. allTrue([true,true,true,true]) --> true // or just array.every(function(x){return x}); |
nbsp;好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | function allDeepEqual(things) { // works with nested arrays if( things.every(isArray) ) return allCompareEqual(things.map(getLength)) // all arrays of same length && allTrue(zip(things).map(allDeepEqual)); // elements recursively equal //else if( this.every(isObject) ) // return {all have exactly same keys, and for // each key k, allDeepEqual([o1[k],o2[k],...])} // e.g. ... && allTrue(objectZip(objects).map(allDeepEqual)) //else if( ... ) // extend some more else return allCompareEqual(things); } |
演示:好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | allDeepEqual([ [], [], [] ]) true allDeepEqual([ [1], [1], [1] ]) true allDeepEqual([ [1,2], [1,2] ]) true allDeepEqual([ [[1,2],[3]], [[1,2],[3]] ]) true allDeepEqual([ [1,2,3], [1,2,3,4] ]) false allDeepEqual([ [[1,2],[3]], [[1,2],[],3] ]) false allDeepEqual([ [[1,2],[3]], [[1],[2,3]] ]) false allDeepEqual([ [[1,2],3], [1,[2,3]] ]) false |
要像使用常规函数一样使用此函数,请执行以下操作:好的。
1 2 3 | function allDeepEqual2() { return allDeepEqual([].slice.call(arguments)); } |
演示:好的。
1 2 | allDeepEqual2([[1,2],3], [[1,2],3]) true |
选项3好的。
编辑:现在是2016年,我以前的回答过于复杂,让我心烦。这种递归的、命令式的"递归编程101"实现使代码非常简单,而且在最早可能的时候失败(给我们效率)。它也不会生成多余的临时数据结构(一般来说,函数编程没有任何问题,只是保持这里的整洁)。好的。
如果我们想将此应用于非空数组,我们可以执行seriesofarrays.reduce(arraysequal)。好的。
这是它自己的函数,而不是使用object.defineproperties附加到array.prototype,因为如果我们传入一个未定义的值(如果您想这样做,这是一个很好的设计决策),这将失败,并出现键错误。好的。
这只回答操作系统的原始问题。好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | function arraysEqual(a,b) { /* Array-aware equality checker: Returns whether arguments a and b are == to each other; however if they are equal-lengthed arrays, returns whether their elements are pairwise == to each other recursively under this definition. */ if (a instanceof Array && b instanceof Array) { if (a.length!=b.length) // assert same length return false; for(var i=0; i<a.length; i++) // assert each element equal if (!arraysEqual(a[i],b[i])) return false; return true; } else { return a==b; // if not both arrays, should be the same } } |
实例:好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | arraysEqual([[1,2],3], [[1,2],3]) true arraysEqual([1,2,3], [1,2,3,4]) false arraysEqual([[1,2],[3]], [[1,2],[],3]) false arraysEqual([[1,2],[3]], [[1],[2,3]]) false arraysEqual([[1,2],3], undefined) false arraysEqual(undefined, undefined) true arraysEqual(1, 2) false arraysEqual(null, null) true arraysEqual(1, 1) true arraysEqual([], 1) false arraysEqual([], undefined) false arraysEqual([], []) true |
如果您想将此应用于具有JS对象的类似JSON的数据结构,可以这样做。幸运的是,我们保证所有对象的键都是唯一的,所以遍历对象本身的属性并按键对它们排序,然后断言排序后的键数组是相等的,值数组是相等的,并且只是递归的。我们也可以扩展它来包含地图(其中键也是唯一的)。(然而,如果我们把它扩展到集合,我们会遇到树同构问题http://logic.pdmi.ras.ru/~smal/files/smal_jass08_slides.pdf-幸运的是,它不像一般的图同构那样困难;实际上有一个O(顶点)算法来解决它,但是有效地解决它会变得非常复杂。病理学的情况是,如果你有一套由许多看似不可辨别的物体组成的装置,但进一步检查后,这些物体中的一些可能会随着你深入研究它们而有所不同。您还可以通过使用散列来拒绝几乎所有的情况来解决这个问题。)好的。
选项4:(续2016年版)好的。
这应该适用于大多数对象:好的。
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 53 54 55 56 | function deepEquals(a,b) { if (a instanceof Array && b instanceof Array) return arraysEqual(a,b); if (Object.getPrototypeOf(a)===Object.prototype && Object.getPrototypeOf(b)===Object.prototype) return objectsEqual(a,b); if (a instanceof Map && b instanceof Map) return mapsEqual(a,b); if (a instanceof Set && b instanceof Set) throw"Error: set equality by hashing not implemented." if ((a instanceof ArrayBuffer || ArrayBuffer.isView(a)) && (b instanceof ArrayBuffer || ArrayBuffer.isView(b))) return typedArraysEqual(a,b); return a==b; // see note[1] -- IMPORTANT } function arraysEqual(a,b) { if (a.length!=b.length) return false; for(var i=0; i<a.length; i++) if (!deepEquals(a[i],b[i])) return false; return true; } function objectsEqual(a,b) { var aKeys = Object.getOwnPropertyNames(a); var bKeys = Object.getOwnPropertyNames(b); if (aKeys.length!=bKeys.length) return false; aKeys.sort(); bKeys.sort(); for(var i=0; i<aKeys.length; i++) if (aKeys[i]!=bKeys[i]) // keys must be strings return false; return deepEquals(aKeys.map(k=>a[k]), aKeys.map(k=>b[k])); } function mapsEqual(a,b) { if (a.size!=b.size) return false; var aPairs = Array.from(a); var bPairs = Array.from(b); aPairs.sort((x,y) => x[0]<y[0]); bPairs.sort((x,y) => x[0]<y[0]); for(var i=0; i<a.length; i++) if (!deepEquals(aPairs[i][0],bPairs[i][0]) || !deepEquals(aPairs[i][1],bPairs[i][1])) return false; return true; } function typedArraysEqual(a,b) { a = new Uint8Array(a); b = new Uint8Array(b); if (a.length != b.length) return false; for(var i=0; i<a.length; i++) if (a[i]!=b[i]) return false; return true; } |
演示(未经广泛测试):好的。
1 2 3 4 5 6 | var nineTen = new Float32Array(2); nineTen[0]=9; nineTen[1]=10; deepEquals( [[1,[2,3]], 4, {a:5,b:6}, new Map([['c',7],['d',8]]), nineTen], [[1,[2,3]], 4, {b:6,a:5}, new Map([['d',8],['c',7]]), nineTen] ) |
(旁注:地图是ES6字典。我不知道它们是否具有O(1)或O(log(n))查找性能,但在任何情况下,它们都是"有序的",因为它们跟踪插入键值对的顺序。但是,如果元素以不同的顺序插入到两个映射中,那么两个映射是否应该相等的语义是不明确的。我在下面给出了一个deepequals的示例实现,该deepequals认为两个映射是相等的,即使元素以不同的顺序插入它们。)好的。
(注[1]:重要提示:平等的概念:您可能希望用一个自定义的平等概念来覆盖所标注的行,在它出现的任何地方,您还必须更改其他函数。例如,是否要NaN==NaN?默认情况下,情况并非如此。还有更奇怪的事情,比如0='0'。如果并且仅当两个对象在内存中是同一个对象时,您认为它们是相同的吗?请参阅https://stackoverflow.com/a/5447170/711085。你应该记录下你所使用的平等的概念。)好的。
您应该能够将上述扩展到weakmaps、weaksets。不确定扩展到数据视图是否有意义。还应该能够扩展到regexps,可能等等。好的。
当你扩展它时,你会意识到你做了很多不必要的比较。这就是我之前定义的
1 2 3 4 5 6 7 8 9 10 | var dispatchTypeEquals = { number: function(a,b) {...a==b...}, array: function(a,b) {...deepEquals(x,y)...}, ... } function deepEquals(a,b) { var typeA = extractType(a); var typeB = extractType(a); return typeA==typeB && dispatchTypeEquals[typeA](a,b); } |
好啊。
jquery没有用于比较数组的方法。然而,下划线库(或类似的lodash库)确实有这样一种方法:isequal,它还可以处理各种其他情况(如对象文本)。要坚持提供的示例:
1 2 3 4 5 | var a=[1,2,3]; var b=[3,2,1]; var c=new Array(1,2,3); alert(_.isEqual(a, b) +"|" + _.isEqual(b, c)); |
顺便说一句:下划线还有许多其他的方法,jquery也缺少,所以它是jquery的一个很好的补充。
编辑:正如注释中所指出的,只有当两个数组的元素顺序相同时,上面的内容才有效,即:
1 2 | _.isEqual([1,2,3], [1,2,3]); // true _.isEqual([1,2,3], [3,2,1]); // false |
幸运的是,javascript有一个内置的方法来解决这个确切的问题,
1 | _.isEqual([1,2,3].sort(), [3,2,1].sort()); // true |
对于像数字和字符串这样的基元值,这是一个简单的解决方案:
1 2 3 4 5 | a = [1,2,3] b = [3,2,1] a.sort().toString() == b.sort().toString() |
调用
使用1.6版的javascript,就这么简单:
1 2 3 4 | Array.prototype.equals = function( array ) { return this.length == array.length && this.every( function(this_i,i) { return this_i == array[i] } ) } |
例如,
即使这看起来非常简单,有时也非常有用。如果您只需要查看两个数组是否具有相同的项,并且它们的顺序相同,请尝试以下操作:
1 2 3 4 5 6 | [1, 2, 3].toString() == [1, 2, 3].toString() true [1, 2, 3,].toString() == [1, 2, 3].toString() true [1,2,3].toString() == [1, 2, 3].toString() true |
但是,这不适用于模式高级情况,例如:
1 2 | [[1,2],[3]].toString() == [[1],[2,3]].toString() true |
这取决于你需要什么。
根据TimJamesAnswer和Fox32的评论,下面应该检查空值,假设两个空值不相等。
1 2 3 4 5 6 7 8 9 10 11 12 | function arrays_equal(a,b) { return !!a && !!b && !(a<b || b<a); } > arrays_equal([1,2,3], [1,3,4]) false > arrays_equal([1,2,3], [1,2,3]) true > arrays_equal([1,3,4], [1,2,3]) false > arrays_equal(null, [1,2,3]) false > arrays_equal(null, null) false |
jquery有这样的方法来进行深度递归比较。
国内通用的严格平等检查可以如下所示:
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 | function deepEquals(obj1, obj2, parents1, parents2) { "use strict"; var i; // compare null and undefined if (obj1 === undefined || obj2 === undefined || obj1 === null || obj2 === null) { return obj1 === obj2; } // compare primitives if (typeof (obj1) !== 'object' || typeof (obj2) !== 'object') { return obj1.valueOf() === obj2.valueOf(); } // if objects are of different types or lengths they can't be equal if (obj1.constructor !== obj2.constructor || (obj1.length !== undefined && obj1.length !== obj2.length)) { return false; } // iterate the objects for (i in obj1) { // build the parents list for object on the left (obj1) if (parents1 === undefined) parents1 = []; if (obj1.constructor === Object) parents1.push(obj1); // build the parents list for object on the right (obj2) if (parents2 === undefined) parents2 = []; if (obj2.constructor === Object) parents2.push(obj2); // walk through object properties if (obj1.propertyIsEnumerable(i)) { if (obj2.propertyIsEnumerable(i)) { // if object at i was met while going down here // it's a self reference if ((obj1[i].constructor === Object && parents1.indexOf(obj1[i]) >= 0) || (obj2[i].constructor === Object && parents2.indexOf(obj2[i]) >= 0)) { if (obj1[i] !== obj2[i]) { return false; } continue; } // it's not a self reference so we are here if (!deepEquals(obj1[i], obj2[i], parents1, parents2)) { return false; } } else { // obj2[i] does not exist 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 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | // message is displayed on failure // clean console === all tests passed function assertTrue(cond, msg) { if (!cond) { console.log(msg); } } var a = 'sdf', b = 'sdf'; assertTrue(deepEquals(b, a), 'Strings are equal.'); b = 'dfs'; assertTrue(!deepEquals(b, a), 'Strings are not equal.'); a = 9; b = 9; assertTrue(deepEquals(b, a), 'Numbers are equal.'); b = 3; assertTrue(!deepEquals(b, a), 'Numbers are not equal.'); a = false; b = false; assertTrue(deepEquals(b, a), 'Booleans are equal.'); b = true; assertTrue(!deepEquals(b, a), 'Booleans are not equal.'); a = null; assertTrue(!deepEquals(b, a), 'Boolean is not equal to null.'); a = function () { return true; }; assertTrue(deepEquals( [ [1, 1, 1], [2, 'asdf', [1, a]], [3, { 'a': 1.0 }, true] ], [ [1, 1, 1], [2, 'asdf', [1, a]], [3, { 'a': 1.0 }, true] ]), 'Arrays are equal.'); assertTrue(!deepEquals( [ [1, 1, 1], [2, 'asdf', [1, a]], [3, { 'a': 1.0 }, true] ], [ [1, 1, 1], [2, 'asdf', [1, a]], [3, { 'a': '1' }, true] ]), 'Arrays are not equal.'); a = { prop: 'val' }; a.self = a; b = { prop: 'val' }; b.self = a; assertTrue(deepEquals(b, a), 'Immediate self referencing objects are equal.'); a.prop = 'shmal'; assertTrue(!deepEquals(b, a), 'Immediate self referencing objects are not equal.'); a = { prop: 'val', inside: {} }; a.inside.self = a; b = { prop: 'val', inside: {} }; b.inside.self = a; assertTrue(deepEquals(b, a), 'Deep self referencing objects are equal.'); b.inside.self = b; assertTrue(!deepEquals(b, a), 'Deep self referencing objects are not equeal. Not the same instance.'); b.inside.self = {foo: 'bar'}; assertTrue(!deepEquals(b, a), 'Deep self referencing objects are not equal. Completely different object.'); a = {}; b = {}; a.self = a; b.self = {}; assertTrue(!deepEquals(b, a), 'Empty object and self reference of an empty object.'); |
检查数组的大小后,通过for循环检查每个值。
1 2 3 4 5 6 7 8 9 10 11 12 | function equalArray(a, b) { if (a.length === b.length) { for (var i = 0; i < a.length; i++) { if (a[i] !== b[i]) { return false; } } return true; } else { return false; } } |
使用
1 2 3 4 5 6 7 8 9 | function arraysEqual (a1, a2) { return a1 === a2 || ( a1 !== null && a2 !== null && a1.length === a2.length && a1 .map(function (val, idx) { return val === a2[idx]; }) .reduce(function (prev, cur) { return prev && cur; }, true) ); } |
要做到这一点并不容易。我也需要这个,但我想要一个函数,它可以接受任意两个变量,并测试是否相等。包括非对象值、对象、数组和任何级别的嵌套。
在您的问题中,您提到希望忽略数组中值的顺序。我的解决方案本身并没有这样做,但是您可以通过在比较是否相等之前对数组进行排序来实现这一点。
我还想要将非对象强制转换为字符串的选项,以便[1,2]===["1",2]
因为我的项目使用了下划线,所以我决定将它作为一个混合函数,而不是一个独立的函数。
你可以在http://jsfiddle.net/nemesarial/t44w4上测试它。/
这是我的MXIN:
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 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | _.mixin({ /** Tests for the equality of two variables valA: first variable valB: second variable stringifyStatics: cast non-objects to string so that"1"===1 **/ equal:function(valA,valB,stringifyStatics){ stringifyStatics=!!stringifyStatics; //check for same type if(typeof(valA)!==typeof(valB)){ if((_.isObject(valA) || _.isObject(valB))){ return false; } } //test non-objects for equality if(!_.isObject(valA)){ if(stringifyStatics){ var valAs=''+valA; var valBs=''+valB; ret=(''+valA)===(''+valB); }else{ ret=valA===valB; } return ret; } //test for length if(_.size(valA)!=_.size(valB)){ return false; } //test for arrays first var isArr=_.isArray(valA); //test whether both are array or both object if(isArr!==_.isArray(valB)){ return false; } var ret=true; if(isArr){ //do test for arrays _.each(valA,function(val,idx,lst){ if(!ret){return;} ret=ret && _.equal(val,valB[idx],stringifyStatics); }); }else{ //do test for objects _.each(valA,function(val,idx,lst){ if(!ret){return;} //test for object member exists if(!_.has(valB,idx)){ ret=false; return; } // test for member equality ret=ret && _.equal(val,valB[idx],stringifyStatics); }); } return ret; } }); |
这就是你如何使用它:
1 | _.equal([1,2,3],[1,2,"3"],true) |
要演示嵌套,可以执行以下操作:
1 2 3 4 5 6 7 8 9 10 | _.equal( ['a',{b:'b',c:[{'someId':1},2]},[1,2,3]], ['a',{b:'b',c:[{'someId':"1 <p><center>[wp_ad_camp_3]</center></p><hr><P>如果您希望检查对象数组的相等性和顺序并不重要,即</P><P><wyn>areequal([id:"0<hr><P>如果您使用的是lodash并且不想修改任何一个数组,那么可以使用函数uxor()。它将两个数组作为集合进行比较,并返回包含差异的集合。如果此差的长度为零,则两个数组基本上相等:</P>[cc lang="javascript"]var a = [1, 2, 3]; var b = [3, 2, 1]; var c = new Array(1, 2, 3); _.xor(a, b).length === 0 true _.xor(b, c).length === 0 true |
It handle all possible stuff and even reference itself in structure of object. You can see the example at the end of code.
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 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | var deepCompare = (function() { function internalDeepCompare (obj1, obj2, objects) { var i, objPair; if (obj1 === obj2) { return true; } i = objects.length; while (i--) { objPair = objects[i]; if ( (objPair.obj1 === obj1 && objPair.obj2 === obj2) || (objPair.obj1 === obj2 && objPair.obj2 === obj1) ) { return true; } } objects.push({obj1: obj1, obj2: obj2}); if (obj1 instanceof Array) { if (!(obj2 instanceof Array)) { return false; } i = obj1.length; if (i !== obj2.length) { return false; } while (i--) { if (!internalDeepCompare(obj1[i], obj2[i], objects)) { return false; } } } else { switch (typeof obj1) { case"object": // deal with null if (!(obj2 && obj1.constructor === obj2.constructor)) { return false; } if (obj1 instanceof RegExp) { if (!(obj2 instanceof RegExp && obj1.source === obj2.source)) { return false; } } else if (obj1 instanceof Date) { if (!(obj2 instanceof Date && obj1.getTime() === obj2.getTime())) { return false; } } else { for (i in obj1) { if (obj1.hasOwnProperty(i)) { if (!(obj2.hasOwnProperty(i) && internalDeepCompare(obj1[i], obj2[i], objects))) { return false; } } } } break; case"function": if (!(typeof obj2 ==="function" && obj1+"" === obj2+"")) { return false; } break; default: //deal with NaN if (obj1 !== obj2 && obj1 === obj1 && obj2 === obj2) { return false; } } } return true; } return function (obj1, obj2) { return internalDeepCompare(obj1, obj2, []); }; }()); /* var a = [a, undefined, new Date(10), /.+/, {a:2}, function(){}, Infinity, -Infinity, NaN, 0, -0, 1, [4,5],"1","-1","a", null], b = [b, undefined, new Date(10), /.+/, {a:2}, function(){}, Infinity, -Infinity, NaN, 0, -0, 1, [4,5],"1","-1","a", null]; deepCompare(a, b); */ |
1 2 3 4 5 6 | var a= [1, 2, 3, '3']; var b = [1, 2, 3]; var c = a.filter(function (i) { return ! ~b.indexOf(i); }); alert(c.length); |
这个方法很糟糕,但我把它留在这里作为参考,所以其他人会避开这条路径:
使用@ninjageckeco的选项1对我来说效果最好:
1 2 3 4 5 6 7 | Array.prototype.equals = function(array) { return array instanceof Array && JSON.stringify(this) === JSON.stringify(array) ; } a = [1, [2, 3]] a.equals([[1, 2], 3]) // false a.equals([1, [2, 3]]) // true |
它还将处理空值和未定义的大小写,因为我们要将其添加到数组的原型中,并检查另一个参数是否也是数组。