微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

javascript – 将数组作为(多)集合进行比较

我正在寻找一种有效的方式来找出两个数组是否包含相同数量的相等元素(在==意义上),按任何顺序:
foo = {/*some object*/}
bar = {/*some other object*/}

a = [1,2,foo,bar,2]
b = [bar,1]

sameElements(a,b) --> true

PS.请注意,线程中的每个解决方案都使用===而不是==进行比较.这对我的需要是很好的.

解决方法

更新5
我用不同的方法发布了一个新的 answer.

更新

我扩大了code,有可能通过参考或平等检查

只是作为第二个参数传递给做参考检查.

另外我把例子添加到了Brunos JSPerf

>运行在大约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

原文地址:https://www.jb51.cc/js/152823.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐