foo = {/*some object*/} bar = {/*some other object*/} a = [1,2,foo,bar,2] b = [bar,1] sameElements(a,b) --> true
PS.请注意,线程中的每个解决方案都使用===而不是==进行比较.这对我的需要是很好的.
解决方法
@H_502_9@ 更新5我用不同的方法发布了一个新的 answer.
更新
我扩大了code,有可能通过参考或平等检查
只是作为第二个参数传递给做参考检查.
>运行在大约11个操作/ s做参考检查
我会尽快评论这个代码(!),因为我有空余的时间来解释一下,但是现在没有时间去思考.完成
更新2.
像布鲁诺一样,在评论中指出,同样的数据([NaN],[NaN])产生错误
在我看来,这是正确的行为,因为NaN是含糊不清的,应该总是导致一个错误的结果,至少在比较NaN.equals(NaN)时.但他有一个很好的点.
是否
[1,NaN,3]应该等于[1,3,2].
好的,诚实地,我有点被撕裂,不管是否应该,所以我添加了两个标志.
> Number.prototype.equal.NaN
>如果为真
> NaN.equals(NaN)// true
> Array.prototype.equal.NaN
>如果为真
> [NaN] .equals([NaN],true)// true
>注意这只是为了参考检查.由于深度检查会调用Number.prototype.equals
更新3:
我完全错过了排序功能中的2行.
r[0] = a._srt; //DANG i totally missed this line r[1] = b._srt; //And this.
第105行在Fiddle
哪种是重要的,因为它决定了元素的一致顺序.
更新4
我试图优化排序功能,并设法达到约20个操作/秒.
以下是更新的代码,以及更新的fiddle =)
此外,我选择标记排序函数之外的对象,它似乎不再具有性能差异,并且它更易读
这是一个使用Object.defineProperty来添加equals函数的方法
Array,Object,Number,String,Boolean的原型,以避免在一个函数中进行类型检查
性能原因因为我们可以递归地在任何元素上调用.equals.
但是当然,检查对象是否相同可能会导致大对象中的性能问题.
所以如果任何人感觉到不愉快的操纵原生的原型,只需做一个类型检查并把它放在一个功能
Object.defineProperty(Boolean.prototype,"equals",{ enumerable: false,configurable: true,value: function (c) { return this == c; //For booleans simply return the equality } }); Object.defineProperty(Number.prototype,value: function (c) { if (Number.prototype.equals.NaN == true && isNaN(this) && c != c) return true; //let NaN equals NaN if flag set return this == c; // else do a normal compare } }); Number.prototype.equals.NaN = false; //Set to true to return true for NaN == NaN Object.defineProperty(String.prototype,value: Boolean.prototype.equals //the same (now we covered the primitives) }); Object.defineProperty(Object.prototype,value: function (c,reference) { if (true === reference) //If its a check by reference return this === c; //return the result of comparing the reference if (typeof this != typeof c) { return false; //if the types don't match (Object equals primitive) immediately return } var d = [Object.keys(this),Object.keys(c)],//create an array with the keys of the objects,which get compared f = d[0].length; //store length of keys of the first obj (we need it later) if (f !== d[1].length) {//If the Objects differ in the length of their keys return false; //immediately return } for (var e = 0; e < f; e++) { //iterate over the keys of the first object if (d[0][e] != d[1][e] || !this[d[0][e]].equals(c[d[1][e]])) { return false; //if either the key name does not match or the value does not match,return false. a call of .equal on 2 primitives simply compares them as e.g Number.prototype.equal gets called } } return true; //everything is equal,return true } }); Object.defineProperty(Array.prototype,reference) { var d = this.length; if (d != c.length) { return false; } var f = Array.prototype.equals.sort(this.concat()); c = Array.prototype.equals.sort(c.concat(),f) if (reference){ for (var e = 0; e < d; e++) { if (f[e] != c[e] && !(Array.prototype.equals.NaN && f[e] != f[e] && c[e] != c[e])) { return false; } } } else { for (var e = 0; e < d; e++) { if (!f[e].equals(c[e])) { return false; } } } return true; } }); Array.prototype.equals.NaN = false; //Set to true to allow [NaN].equals([NaN]) //true Object.defineProperty(Array.prototype.equals,"sort",{ enumerable:false,value:function sort (curr,prev) { var weight = { "[object Undefined]":6,"[object Object]":5,"[object Null]":4,"[object String]":3,"[object Number]":2,"[object Boolean]":1 } if (prev) { //mark the objects for (var i = prev.length,j,t;i>0;i--) { t = typeof (j = prev[i]); if (j != null && t === "object") { j._pos = i; } else if (t !== "object" && t != "undefined" ) break; } } curr.sort (sorter); if (prev) { for (var k = prev.length,l,t;k>0;k--) { t = typeof (l = prev[k]); if (t === "object" && l != null) { delete l._pos; } else if (t !== "object" && t != "undefined" ) break; } } return curr; function sorter (a,b) { var tStr = Object.prototype.toString var types = [tStr.call(a),tStr.call(b)] var ret = [0,0]; if (types[0] === types[1] && types[0] === "[object Object]") { if (prev) return a._pos - b._pos else { return a === b ? 0 : 1; } } else if (types [0] !== types [1]){ return weight[types[0]] - weight[types[1]] } return a>b?1:a<b?-1:0; } } });
这样我们可以减少相同的元素功能
function sameElements(c,d,referenceCheck) { return c.equals(d,referenceCheck); //call .equals of Array.prototype. }
注意.当然,您可以将所有相同的函数放在同一个元素函数中,用于类型检查的成本.
现在这里有3个例子:1,深入检查,2个参考检查.
var foo = { a: 1,obj: { number: 2,bool: true,string: "asd" },arr: [1,3] }; var bar = { a: 1,3] }; var foobar = { a: 1,4] }; var a = [1,2]; var b = [foo,1]; var c = [bar,1];
所以这些是我们比较的数组.输出是
>检查a和b只有参考.
console.log(sameElements(a,b,true))// true它们包含相同的元素
>检查b和c只有参考
console.log(sameElements(b,c,true))// false,因为c包含两次.
>深入检查b和c
console.log(sameElements(b,false))// true,因为bar和foo是相等但不一样的
>检查包含NaN的2个数组
Array.prototype.equals.NaN = true;
的console.log(sameElements([NaN的],[NaN的],真)); //真正.
Array.prototype.equals.NaN = false;
演示JSFiddle