Compare arrays as (multi-) sets

前端 未结 8 1658
梦如初夏
梦如初夏 2021-01-04 21:42

I\'m looking for an efficient way to find out whether two arrays contain same amounts of equal elements (in the == sense), in any order:

foo = {         


        
8条回答
  •  -上瘾入骨i
    2021-01-04 22:04

    Edit 2
    1) Thanks to user2357112 for pointing out the Object.prototype.toString.call issue this also showed, the reason it was that fast, that it didn't consider Arrays ...

    I fixed the code,it should be working now :), unfortunately its now at about 59ops/s on chrome and 45ops/s on ff.

    Fiddle and JSPerf is updated.

    Edit
    1) I fixed the code, it supports mutliple variables referencing the same Object now. A little bit slower than before, but still over 100ops/s on chrome.

    2) I tried using a bitmask instead of an array to keep multiple positions of the objects, but its nearly 15ops/s slow

    3) As pointed ot in the comments i forgot to reset tmp after [[get]] is called fixed the code, the fiddle, and the perf.


    So thanks to user2357112 with his Answer heres another approach using counting

    var sameElements = (function () {
        var f, of, objectFlagName;
        of = objectFlagName = "__pos";
        var tstr = function (o) {
            var t = typeof o;
            if (o === null)
                t = "null";
            return t
        };
        var types = {};
        (function () {
            var tmp = {};
            Object.defineProperty(types, tstr(1), {
                set: function (v) {
                    if (f)
                        tmp[v] = -~tmp[v];
                    else
                        tmp[v] = ~-tmp[v];
                },
                get: function () {
                    var ret = 1;
                    for (var k in tmp) {
                        ret &= !tmp[k];
                    }
                    tmp = {};
                    return ret;
                }
            });
        })();
        (function () {
            var tmp = {};
            Object.defineProperty(types, tstr(""), {
    
                set: function (v) {
                    if (f) {
                        tmp[v] = -~tmp[v];
                    } else {
    
                        tmp[v] = ~-tmp[v];
                    }
                },
                get: function () {
                    var ret = 1;
                    for (var k in tmp) {
                        ret &= !tmp[k];
                    }
                    tmp = {};                
                    return ret;
                }
            });
        })();
    
        (function () {
            var tmp = [];
            function add (v) {
                tmp.push(v);
                if (v[of]===undefined) {
                    v[of] = [tmp.length -1];
                } else {
                    v[of].push(tmp.length -1)
                }            
    
            }
            Object.defineProperty(types, tstr({}), {
                get: function () {
                    var ret = true;
                    for (var i = tmp.length - 1; i >= 0; i--) {
                        var c = tmp[i]
                        if (typeof c !== "undefined") {
                            ret = false
                            delete c[of]
                        }
                    }
                    tmp = [];
                    return ret;
                },
                set: function (v) {
                    var pos;
                    if (f) {
                        add (v);
                    } else if (!f && (pos = v[of]) !== void 0) {
                           tmp[pos.pop()] = undefined;
                           if (pos.length === 0)
                                delete v[of];
                    } else {
                            add (v);
                    }
                }
            });
        }());
        (function () {
            var tmp = 0;
            Object.defineProperty(types, tstr(undefined), {
                get: function () {
                    var ret = !tmp;
                    tmp = 0;
                    return ret;
    
                },
                set: function () {
                    tmp += f ? 1 : -1;
                }
            });
        })();
        (function () {
            var tmp = 0;
            Object.defineProperty(types, tstr(null), {
                get: function () {
                    var ret = !tmp;
                    tmp = 0;
                    return ret;
                },
                set: function () {
                    tmp += f ? 1 : -1;
                }
            });
        })();
    
        var tIt = [tstr(1), tstr(""), tstr({}), tstr(undefined), tstr(null)];
    
        return function eq(a, b) {
    
            f = true;
            for (var i = a.length - 1; i >= 0; i--) {
                var v = a[i];
                types[tstr(v)] = v;
            }
            f = false;
            for (var k = b.length - 1; k >= 0; k--) {
                var w = b[k];
                types[tstr(w)] = w;
            }
            var r = 1;
            for (var l = 0, j; j = tIt[l]; l++) {
                r &= types [j]
            }
    
            return !!r;
        }
        })()
    

    Here is a JSFiddle and a JSPerf (it uses the same Arrays a and b as in the previous answers perf) with this code vs the Closure compiled

    Heres the output. note: it doesn't support a deep comparison anymore, as is

    var foo = {a:2}    
    var bar = {a:1};
    var a = [1, 2, foo, 2, bar, 2];
    var b = [foo, 2, 2, 2, bar, 1];
    var c = [bar, 2, 2, 2, bar, 1];
    console.log(sameElements([NaN],[NaN])); //true
    console.log (sameElements ( a,b))  //true
    console.log (sameElements (b,c))   //false
    

提交回复
热议问题