通过keyname从javascript对象中删除值列表的最有效方法

时间:2015-01-12 06:57:04

标签: javascript optimization

我需要找到一种最有效的方法,可以根据“要删除的键”列表从任意嵌套的javascript对象中删除值。即。

var obj = {a:1, b:2, c:{d:1, e:1}};
var ignoreList = ["a","e"] (could also be ['a', 'c.e'])
removeIgnoredValues(obj, ignoreList) => {b:2, c:{d:1}}.

现在很明显,如果你不关心效率,这很容易做到,而且我目前的实施一直很好地为我服务。但现在我不得不处理具有6级和大数据数组的对象。

如果有人有解决方案或链接到一个非常棒的那个:)

干杯

编辑:当前的实现看起来像这样。它有效(并处理循环引用)。但是太慢了。

/**
 * Returns a sanitised string of an object, removing any functions and unwanted properties.
 * @param {int} obj. The object to be stringified
 * @param {Array[]} ignoreList. A array of object properties that should be removed.
 */
function sanitise(obj, ignoreList){
    if(obj == undefined){
        throw "Can't sanitise an undefined object"
    }
    var entry = JSON.parse(JSON.stringifyOnce(obj));
    for(var i in entry){
        if(entry.hasOwnProperty(i)){
            if(contains(ignoreList, i)){
                delete entry[i];
            } else if(typeof(entry[i]) == "object" && entry[i] != null){
                entry[i] = sanitise(entry[i], ignoreList);
            }
        }
    }
    return entry;
}

JSON.stringifyOnce = function(obj, replacer, indent){
    var printedObjects = [];
    var printedObjectKeys = [];

    function printOnceReplacer(key, value){
        var printedObjIndex = false;
        printedObjects.forEach(function(obj, index){
            if(obj===value){
                printedObjIndex = index;
            }
        });

        if ( key == ''){ //root element
             printedObjects.push(obj);
            printedObjectKeys.push("root");
             return value;
        }

        else if(printedObjIndex+"" != "false" && typeof(value)=="object"){
            if ( printedObjectKeys[printedObjIndex] == "root"){
                return "(pointer to root)";
            }else{
                return "(see " + ((!!value && !!value.constructor) ? value.constructor.name.toLowerCase()  : typeof(value)) + " with key " + printedObjectKeys[printedObjIndex] + ")";
            }
        }else{

            var qualifiedKey = key || "(empty key)";
            printedObjects.push(value);
            printedObjectKeys.push(qualifiedKey);
            if(replacer){
                return replacer(key, value);
            }else{
                return value;
            }
        }
    }
    return JSON.stringify(obj, printOnceReplacer, indent);
};

2 个答案:

答案 0 :(得分:0)

我们可以为原始对象创建一个查找表对象,以便在O(1)时间内删除任何给定的键。实现将涉及添加自定义函数以添加/删除对象。

(function() {
    var lookUpTable = {};
    myObj.prototype.insert = function(key, value) {
        // add key to the myObj
        // insert an Entry for parent of key in lookUpTable
        // lookUpTable = { "a" : [myObj.b, myObj, myObj.c.d.e] }
    }

    myObj.prototype.ignore = function(ignoreList) {
        for( key in ignoreList ) {
             for( parent in lookUpTable[key] )
                  delete parent[key];
             delete lookUpTable [key];
        }
    }
}());

现在您可以调用insert函数来插入键值:

myObj.insert('a.b.c.d', ['p', 'g']);

并调用ignore函数删除对象:

myObj.ignore(['d', 'e']);

很抱歉只提供不完整的代码。但是,您应该能够轻松地实现细节。希望你明白这一点。

对于您给出的示例:

obj = {a:[{b:1, c:1}, {b:1, c:1}, {b:1, c:1}] 

并且您想忽略所有' b。请注意,查找表条目值是数组,而不仅仅是单个值。这就是忽略具有相同名称的多个条目的强大功能。在这种情况下,' b'会是这样的。

lookupTable = {
                  b : [           // The parent objects of 'b'
                          obj['a'][0],
                          obj['a'][1],
                          obj['a'][2]
                       ]
              }

基本上,lookuptable包含对包含键'b'的所有对象的引用数组。因此,您遍历每个父对象并删除它们的'b'条目。

$.each(lookupTable['b'], function( parent ) {
    delete parent['b']; // Deletes 'b' inside of every parent object
});

在插入obj或第一次加载obj时填充此查找表条目。如果obj是硬编码的,您还可以生成lookupTable一次并对其进行硬编码。可能与你的minify Javascript脚本一起。虽然在运行时填充它也很安静。

答案 1 :(得分:0)

好的,想出了一个非常好的方法。您只需创建一个忽略列表,其中的对象结构与要忽略的对象大致相同。

function ignore(obj, list){
    for(var i in list){
        var type = Object.prototype.toString.call(list[i]);

        if(type == "[object String]"){
            delete obj[i];
        } 

        else if (type == "[object Object]"){
            ignore(obj[i], list[i])
        } 

        else if (type == "[object Array]"){
            var objList = obj[i];
            var subList = list[i][0];

            for(var n in objList){
                ignore(objList[n], subList)
            }
        }
    }
}

x = {a:1, b:[{c:1, d:1}, {c:1, d:1}, {c:1, d:1}], e:1}
ignoreList = {'e':'e', 'b':[{'c':'c'}]}
ignore(x, ignoreList) => {a:1, b:[{d:1}, {d:1}, {d:1}]}