按键名从javascript对象中删除值列表的最有效方法

按键名从javascript对象中删除值列表的最有效方法,javascript,optimization,Javascript,Optimization,我需要找到最有效的方法,根据“要删除的键”列表从任意嵌套的javascript对象中删除值。i、 e 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}}. 现在很明显,如果您不关心效率的话,这是很容易做到的,我目前的实现到目前为止一直为我服务。但现在

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

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);
};

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

(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”条目


在插入obj或首次加载obj时填充此查找表条目。如果obj是硬编码的,您还可以生成lookupTable一次并硬编码它。可能与您的缩小Javascript脚本一起使用。尽管在运行时填充它也很好。

好的,找到了一个非常好的方法。您只需创建一个与要忽略的对象具有大致相同的对象结构的忽略列表

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}]}

不用担心,不完整的代码是可以的。这样的解决方案确实出现了,但它不适合以下用例:obj={a:[{b:1,c:1},{b:1,c:1},{b:1,c:1}]然后忽略b或c。我能想到的唯一处理方法是能够向忽略列表中添加像a~b这样的内容,这将由一个函数对列表进行迭代来解释。但这有点复杂,因此首先要问:D@user1812406添加了一些关于如何处理示例的说明您已经给出了。这个示例将清楚地说明我的意思。基本上,查找表包含键的父项数组,而不是单个引用。因此,可以处理具有相同键的多个条目。
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}]}