Koe*_*err 225 javascript
var a = [1, 2, 3];
var b = [3, 2, 1];
var c = new Array(1, 2, 3);
alert(a == b + "|" + b == c);
Run Code Online (Sandbox Code Playgroud)
如何检查这些数组是否相等并获得一个方法,true如果它们相等则返回?
jQuery是否提供任何方法?
eny*_*nyo 251
这是你应该做的.请不要使用stringify也不< >.
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;
}
Run Code Online (Sandbox Code Playgroud)
nin*_*cko 132
选项1
最简单的选项,几乎适用于所有情况,除了null!== undefined但它们都转换为JSON表示null并被视为相等:
function arraysEqual(a1,a2) {
/* WARNING: arrays must not contain {objects} or behavior may be undefined */
return JSON.stringify(a1)==JSON.stringify(a2);
}
Run Code Online (Sandbox Code Playgroud)
(如果您的数组包含对象,这可能不起作用.这是否仍然适用于对象取决于JSON实现是否对键进行排序.例如,JSON {1:2,3:4}可能或可能不等于{3:4,1:2};这取决于实现,并且规范使[2017更新:实际上,ES6规范现在保证对象键将按照以下顺序迭代:1)整数属性,2)属性按照它们被定义的顺序,然后3)符号属性按它们被定义的顺序.因此,如果JSON.stringify实现遵循此,则相等的对象(在===意义上但在==意义上不是NECESSARILY)将字符串化为相等的值.需要更多的研究.所以我猜你可以用相反的顺序制作一个具有属性的对象的邪恶克隆,但我无法想象它偶然发生...] 至少在Chrome上,JSON.stringify函数倾向于按顺序返回键定义了(至少我注意到了),但这种行为在任何时候都很容易改变,不应该依赖.如果您选择不在列表中使用对象,这应该可以正常工作.如果列表中的对象都具有唯一ID,则可以执行此操作a1.map(function(x)}{return {id:x.uniqueId}}).如果列表中有任意对象,则可以继续阅读选项#2.)
这也适用于嵌套数组.
然而,由于创建这些字符串和垃圾收集它们的开销,它的效率稍低.
选项2
更多"正确"选项,您可以覆盖它以处理特殊情况(如常规对象和null/undefined和自定义对象,如果您愿意):
// 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]})
});
}
Run Code Online (Sandbox Code Playgroud)
// 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});
Run Code Online (Sandbox Code Playgroud)
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);
}
Run Code Online (Sandbox Code Playgroud)
演示:
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
Run Code Online (Sandbox Code Playgroud)
要像常规函数一样使用它,请执行以下操作:
function allDeepEqual2() {
return allDeepEqual([].slice.call(arguments));
}
Run Code Online (Sandbox Code Playgroud)
演示:
allDeepEqual2([[1,2],3], [[1,2],3])
true
Run Code Online (Sandbox Code Playgroud)
选项3
编辑:这是2016年,我以前过于复杂的答案让我烦恼.这种递归的,命令式的"递归编程101"实现使代码非常简单,并且在尽可能早的时候失败(给我们效率).它也不会产生多余的短暂数据结构(并不是说函数编程通常有任何问题,只是在这里保持干净).
如果我们想将它应用于非空数组数组,我们可以执行seriesOfArrays.reduce(arraysEqual).
这是它自己的函数,而不是使用Object.defineProperties连接到Array.prototype,因为如果我们传入一个未定义的值(如果你想这样做,那么这是一个很好的设计决定)会因为键错误而失败.
这只回答OP原始问题.
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
}
}
Run Code Online (Sandbox Code Playgroud)
例子:
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
Run Code Online (Sandbox Code Playgroud)
如果你想用js对象将它应用于类似JSON的数据结构,你可以这样做.幸运的是,我们保证所有对象键都是唯一的,因此迭代对象OwnProperties并按键对它们进行排序,然后断言排序的键数组相等且值数组相等,并且只是递归.我们可以扩展它以包括地图(其中键也是唯一的).(但是如果我们将它扩展到Sets,我们会遇到树同构问题http://logic.pdmi.ras.ru/~smal/files/smal_jass08_slides.pdf - 幸运的是它并不像一般的图同构那么难;有事实上是一个O(#vertices)算法来解决它,但它可以变得非常复杂有效地完成它.病理情况是如果你有一个由许多看似无法区分的对象组成的集合,但是在进一步检查时会有一些这些对象你可以深入研究它们.你也可以通过使用散列来解决几乎所有情况.)
选项4 :(继续编辑2016年)
这适用于大多数对象:
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;
}
Run Code Online (Sandbox Code Playgroud)
演示(未经过广泛测试):
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]
)
Run Code Online (Sandbox Code Playgroud)
(旁注:地图是es6词典.我不知道它们是否具有O(1)或O(log(N))查找性能,但无论如何它们都是"有序"的,因为它们跟踪顺序但是,如果元素以不同的顺序插入到它们中,两个Maps是否应该相等的语义是不明确的.我给出了一个深度平等的示例实现,它认为两个映射相等如果元素以不同的顺序插入它们.)
(注释[1]:重要:平等的注释:您可能希望使用自定义的相等概念覆盖注释的行,您必须在其出现的任何位置更改其他功能.例如,您是否要做你想要NaN == NaN吗?默认情况并非如此.还有更奇怪的事情,比如0 =='0'.你是否认为两个对象是相同的,当且仅当它们是同一个对象时内存?请参阅/sf/answers/381301931/.您应该记录您使用的相等概念.)
您应该能够将上述内容扩展到WeakMaps,WeakSets.不确定扩展到DataViews是否有意义.也应该可以扩展到RegExps等等.
当你扩展它时,你会发现你做了很多不必要的比较.这是type我之前定义的函数(解决方案#2)可以派上用场的地方; 然后你可以立即发送.这是否值得花费(可能?不确定它是如何在引擎盖下工作)代表类型的字符串取决于你.然后你可以重新调度调度程序,即函数deepEquals,如下所示:
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);
}
Run Code Online (Sandbox Code Playgroud)
mac*_*ost 66
jQuery没有比较数组的方法.然而,Underscore 库(或类似的Lodash库)确实有这样的方法:isEqual,它也可以处理各种其他情况(如对象文字).坚持提供的例子:
var a=[1,2,3];
var b=[3,2,1];
var c=new Array(1,2,3);
alert(_.isEqual(a, b) + "|" + _.isEqual(b, c));
Run Code Online (Sandbox Code Playgroud)
顺便说一句:Underscore还有很多其他jQuery缺失的方法,所以它是jQuery的一个很好的补充.
编辑:正如在评论中指出的,上面现在只有两个数组的元素顺序相同时才有效,即:
_.isEqual([1,2,3], [1,2,3]); // true
_.isEqual([1,2,3], [3,2,1]); // false
Run Code Online (Sandbox Code Playgroud)
幸运的是,Javascript有一个内置的方法来解决这个确切的问题,sort:
_.isEqual([1,2,3].sort(), [3,2,1].sort()); // true
Run Code Online (Sandbox Code Playgroud)
小智 37
对于数字和字符串等原始值,这是一个简单的解决方案:
a = [1,2,3]
b = [3,2,1]
a.sort().toString() == b.sort().toString()
Run Code Online (Sandbox Code Playgroud)
调用sort()将确保元素的顺序无关紧要.该toString()调用将创建一个字符串,其值为逗号分隔,因此可以测试两个字符串是否相等.
rpl*_*iko 22
使用JavaScript 1.6版,它就像这样简单:
Array.prototype.equals = function( array ) {
return this.length == array.length &&
this.every( function(this_i,i) { return this_i == array[i] } )
}
Run Code Online (Sandbox Code Playgroud)
例如,[].equals([])给出true,而[1,2,3].equals( [1,3,2] )产量false.
即使这看起来非常简单,但有时它确实非常有用.如果您只需要查看两个数组是否具有相同的项并且它们的顺序相同,请尝试以下操作:
[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
Run Code Online (Sandbox Code Playgroud)
但是,这不适用于模式高级情况,例如:
[[1,2],[3]].toString() == [[1],[2,3]].toString()
true
Run Code Online (Sandbox Code Playgroud)
这取决于你需要什么.
小智 7
根据Tim James的回答和Fox32的评论,下面应检查空值,假设两个空值不相等.
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
Run Code Online (Sandbox Code Playgroud)
jQuery有这种深度递归比较的方法.
本土的通用严格平等检查可能如下所示:
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;
};
Run Code Online (Sandbox Code Playgroud)
测试:
// 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.');
Run Code Online (Sandbox Code Playgroud)
小智 5
检查数组的大小后,通过 for 循环检查每个值。
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;
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
274248 次 |
| 最近记录: |