检查重复的Javascript对象

TL; DR版本:我想避免将重复的Javascript对象添加到类似对象的数组中,其中一些可能非常大.什么是最好的方法?

我有一个应用程序,我将大量的JSON数据加载到Javascript数据结构中.虽然它比这更复杂,但假设我通过一系列AJAX请求将JSON加载到服务器的Javascript对象数组中,例如:

var myObjects = [];

function processObject(o) {
    myObjects.push(o);
}

for (var x=0; x<1000; x++) {
    $.getJSON('/new_object.json', processObject);
}

更复杂的是,JSON:

>处于未知架构中
>具有任意长度(可能不是很大,但可能在100-200 kb范围内)
>可能包含不同请求的重复项

我最初的想法是有一个额外的对象来存储每个对象的哈希值(通过JSON.stringify?)并在每次加载时检查它,如下所示:

var myHashMap = {};

function processObject(o) {
    var hash = JSON.stringify(o);
    // is it in the hashmap?
    if (!(myHashMap[hash])) {
        myObjects.push(o);
        // set the hashmap key for future checks
        myHashMap[hash] = true;
    }
    // else ignore this object
}

但我担心myHashMap中的属性名称长度可能为200 kb.所以我的问题是:

>对于这个问题,有没有比hashmap想法更好的方法?
>如果没有,是否有更好的方法为JSON.stringify的任意长度和模式的JSON对象创建哈希函数?
>对象中的超长属性名称可能存在哪些问题?

解决方法:

我建议你创建一个JSON.stringify(o)的MD5哈希值,并将其存储在你的hashmap中,并引用你的存储对象作为哈希的数据.并且为了确保JSON.stringify()中没有对象键顺序差异,您必须创建对键进行排序的对象的副本.

然后,当每个新对象进入时,您将根据哈希映射进行检查.如果在哈希映射中找到匹配项,则将传入对象与您存储的实际对象进行比较,以查看它们是否真正重复(因为可能存在MD5哈希冲突).这样,您就拥有了一个可管理的哈希表(其中只有MD5哈希值).

这是用于创建对象的规范字符串表示的代码(包括嵌套对象或数组中的对象),如果您刚刚调用JSON.stringify(),则可以处理可能处于不同顺序的对象键.

// Code to do a canonical JSON.stringify() that puts object properties 
// in a consistent order
// Does not allow circular references (child containing reference to parent)
JSON.stringifyCanonical = function(obj) {
    // compatible with either browser or node.js
    var Set = typeof window === "object" ? window.Set : global.Set;

    // poor man's Set polyfill
    if (typeof Set !== "function") {
        Set = function(s) {
            if (s) {
                this.data = s.data.slice();
            } else {
                this.data = [];
            }
        };
        Set.prototype = {
            add: function(item) {
                this.data.push(item);
            },
            has: function(item) {
                return this.data.indexOf(item) !== -1;
            }
        };
    }

    function orderKeys(obj, parents) {
        if (typeof obj !== "object") {
            throw new Error("orderKeys() expects object type");
        }
        var set = new Set(parents);
        if (set.has(obj)) {
            throw new Error("circular object in stringifyCanonical()");
        }
        set.add(obj);
        var tempObj, item, i;
        if (Array.isArray(obj)) {
            // no need to re-order an array
            // but need to check it for embedded objects that need to be ordered
            tempObj = [];
            for (i = 0; i < obj.length; i++) {
                item = obj[i];
                if (typeof item === "object") {
                    tempObj[i] = orderKeys(item, set);
                } else {
                    tempObj[i] = item;
                }
            }
        } else {
            tempObj = {};
            // get keys, sort them and build new object
            Object.keys(obj).sort().forEach(function(item) {
                if (typeof obj[item] === "object") {
                    tempObj[item] = orderKeys(obj[item], set);
                } else {
                    tempObj[item] = obj[item];
                }
            });
        }
        return tempObj;
    }

    return JSON.stringify(orderKeys(obj));
}

而且,算法

var myHashMap = {};

function processObject(o) {
    var stringifiedCandidate = JSON.stringifyCanonical(o);
    var hash = CreateMD5(stringifiedCandidate);
    var list = [], found = false;
    // is it in the hashmap?
    if (!myHashMap[hash] {
        // not in the hash table, so it's a unique object
        myObjects.push(o);
        list.push(myObjects.length - 1);    // put a reference to the object with this hash value in the list
        myHashMap[hash] = list;             // store the list in the hash table for future comparisons
    } else {
        // the hash does exist in the hash table, check for an exact object match to see if it's really a duplicate
        list = myHashMap[hash];             // get the list of other object indexes with this hash value
        // loop through the list
        for (var i = 0; i < list.length; i++) {
            if (stringifiedCandidate === JSON.stringifyCanonical(myObjects[list[i]])) {
                found = true;       // found an exact object match
                break;
            }
        }
        // if not found, it's not an exact duplicate, even though there was a hash match
        if (!found) {
            myObjects.push(o);
            myHashMap[hash].push(myObjects.length - 1);
        }
    }
}

jsonStringifyCanonical()的测试用例在这里:https://jsfiddle.net/jfriend00/zfrtpqcL/

上一篇:javascript – 从JS数组中删除重复值


下一篇:mysql – 返回重复记录