我有一个嵌套对象,类似于:
var obj = {
"prop1": {
"prop1A": "A",
"prop1B": {
"prop1BA": "BA"
},
"prop1C": "C"
}
};
我的最终目标是根据另一个模式对象将此对象过滤为特定的预定义键,例如:
var filterSchema = {
"prop1":["prop1A", {"prop1B":["prop1BA"]}]
};
(过滤器键是预定义的,如果你有更好的想法,我可以用不同的方式构造这个对象......
输出应该是一个数组。在我们的案例中:
["A","BA"]
我设法使用对象的递归来做到这一点。我想知道是否有更优雅的方式来实现这一点(尝试使用jQuery的map / extend而没有运气)
修改 我知道这是一个“N”级问题,应该通过递归来解决。这里的区别在于我有预定义的过滤器,它已经具有“N”级别。所以我可能会使用过滤器数组过滤Objet,然后将其转换为数组。
EDIT2 谢谢大家的不同答案。这是我自己的问题解决方案(我在开始时寻找更优雅的解决方案): My solution
var obj = {
"prop1": {
"prop1A": "A",
//"prop1B": {
// "prop1BA": "BA"
//},
"prop1C": "C",
"prop1D": "D",
"prop1E": {"prop1E1": "444"}
},
"prop2": "12345"
};
var schemaObj = {
"prop1": {
"prop1A": "true",
"prop1B": {
"prop1BA": "true"
},
"prop1C": "true"
},
"prop2": "true"
};
var resultsArray = [];
var keys = Object.keys(schemaObj);
for(var i=0;i<keys.length;i++){
if(obj[keys[i]]){
parser(schemaObj[keys[i]], obj[keys[i]]);
}
}
function parser(v,o){
if( typeof v === "string" ){
resultsArray.push(o);
}
else{
var keys2 = Object.keys(v);
for(var j=0;j<keys2.length;j++){
if(o[keys2[j]]){
parser(v[keys2[j]], o[keys2[j]]);
}
}
}
}
console.log(resultsArray);
只是提醒一下这个问题 - 我已经有了递归解决方案。我正在寻找一个不同的解决方案
答案 0 :(得分:0)
Javascript具有eval
,允许您在运行时创建新代码。一种可能的解决方案是仅使用递归一次来创建一个看起来像这样的字符串:
code = "[obj.prop1.prop1A, obj.prop1.prop1B.prop1BA]"
然后您可以使用
创建数据转换功能f = eval("function(obj){return " + code + "]}")
并将其与f(x)
一起使用以获取阵列。
如果您必须多次提取数据,这也是最有效的解决方案。
例如:
function mkFilter(schema) {
var parts = [];
function xtract(s, prefix) {
if (typeof s === "string") {
parts.push(prefix + s);
} else if (s && s.constructor === Array) {
s.forEach(function(x){ xtract(x, prefix); });
} else {
for (var f in s) {
xtract(s[f], prefix + f + ".");
}
}
}
xtract(schema, "obj.");
var code = "(function(obj){ return [" + parts.join(", ") + "]; })";
return eval(code);
}
传递schemaFilter
作为参数mkFilter
将返回一个给定对象返回数组的函数;输入您的信息:
console.log(mkFilter(filterSchema)(obj));
显示['A', 'BA']
。当然,如果您需要使用不同的对象多次重复使用相同的过滤器,这种方法是有意义的。
如果对象可能缺少部件,并且您不希望过滤器失败但数组中只有undefined
值,则需要稍微更改代码生成器:
var code = "(function(obj){ return [";
parts.forEach(function(p){
var chain = p.split(".");
var expr = "";
for (var i=0; i<chain.length-1; i++) {
expr += chain.slice(0, i+1).join(".") + " && ";
}
code += expr + p + ",";
});
code += "]; })";
这将在您的示例中创建一个评估
的过滤器(function(obj){
return [obj && obj.prop1 && obj.prop1.prop1A,
obj && obj.prop1 && obj.prop1.prop1B &&
obj.prop1.prop1B.prop1BA,];
})
答案 1 :(得分:0)
以下功能似乎可以满足您的需求:
function filter(obj, schema, out) {
var i, schemaItems, schemaItem, isItemLevel;
if (!obj || !schema) return;
out = out || {values: []};
isItemLevel = Array.isArray(schema);
schemaItems = isItemLevel ? schema : Object.keys(schema);
for (i = 0; i < schemaItems.length; i++) {
schemaItem = schemaItems[i];
if (isItemLevel && typeof schemaItem === "string") {
out.values.push(obj[schemaItem]);
} else if (typeof schemaItem === "object") {
filter(obj, schemaItem, out);
} else if (typeof schemaItem === "string") {
filter(obj[schemaItem], schema[schemaItem], out);
}
}
return out.values;
}
称为
var obj = {
"prop1": {
"prop1A": "A",
"prop1B": {
"prop1BA": "BA"
},
"prop1C": "C"
}
};
var filterSchema = {
"prop1":["prop1A", {"prop1B":["prop1BA"]}]
};
filter(obj, filterSchema);
返回:
["A", "BA"]
带上一粒盐,到现在为止 没有经过充分测试,我当然不认为这是解决这个问题的最优雅方式。
它的工作原理如下:
schema
(可以是数组或对象)的项目schemaItem
schemaItem
是一个字符串,则输出相应的属性值obj
schemaItem
本身就是一个对象,则递归,但在obj
schemaItem
是一个字符串,则递归,同时深入obj
和schema
答案 2 :(得分:0)
使用jquery的map函数。您可以在控制台中尝试示例代码段,但必须包含jquery
a = { aa: '123', ab: 'asdasd'}
$.map(a, function(key,val){
return val;
});
// The map creates an array with the value you return from the code block.
// Output is ["aa", "ab"]