我需要找到一种最有效的方法,可以根据“要删除的键”列表从任意嵌套的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 :(得分: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}]}