2015-01-12 38 views
0

我需要找到最有效的方法来根据“要删除的键”列表从任意嵌套的javascript对象中删除值。即通过键名从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); 
}; 
+0

新增编辑 – BrightEyed

回答

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

现在你可以调用插入功能插入键值:

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

,并调用忽略功能删除对象:

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脚本一起。虽然在运行时填充它也很安静。

+0

不用担心,不完整的代码是好的。我们想到了这样的解决方案,但它不符合以下用例: obj = {a:[{b:1,c:1},{b:1,c:1},{ b:1,c:1}] ,然后忽略b或c。处理我能想到的唯一方法就是能够将一些东西添加到忽略列表中,比如“a〜b”,它将被函数解释为遍历列表。但是这会有点牵扯,因此来这里首先要问:D – BrightEyed

+0

@ user1812406已经添加了一些关于如何处理您提供的示例的解释。这个例子将明确我的意思。基本上查找表拥有一个父母的数组,而不是一个单一的参考。因此,使用相同密钥的多个条目处理得很好。 –

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}]} 
相关问题