我有一个动态生成的JavaScript对象,它由嵌套对象和数组组成。我无法找到列出所有嵌套对象的正确方法,因为该特定对象是动态创建的。
这是对象:
var tagdata = {
"Sentence": [{
"NP": [{
"NMP": "cat"
}, {
"NMP": "dog"
}]
}, {
"VP": [{
"KPD": "tree"
}, {
"NP": [{
"NMP": "ball"
}, {
"NMP": "bat"
}]
},{
"NP": [{
"NMP": "ground"
}, {
"NMP": "time"
}]
}]
}]
};
我需要的输出如下所示:
[{ key: 1, text: 'Sentence' },
{ key: 2, text: 'NP', parent: 1 },
{ key: 3, text: 'VP', parent: 1 },
{ key: 4, text: 'NMP', parent: 2 },
{ key: 5, text: 'NMP', parent: 2 },
{ key: 6, text: 'KPD', parent: 3 },
{ key: 7, text: 'NP', parent: 3 },
{ key: 8, text: 'NP', parent: 3 },
{ key: 9, text: 'cat', parent: 4 },
{ key: 10, text: 'dog', parent: 5 },
{ key: 11, text: 'tree', parent: 6 },
{ key: 12, text: 'NMP', parent: 7 },
{ key: 13, text: 'NMP', parent: 7 },
{ key: 14, text: 'NMP', parent: 8 },
{ key: 15, text: 'NMP', parent: 8 },
{ key: 16, text: 'ball', parent: 12},
{ key: 17, text: 'bat', parent: 13},
{ key: 18, text: 'ground', parent: 14},
{ key: 19, text: 'time', parent: 15},]
此数据将在树中使用,因此顺序可能不同,但应保持密钥:父关系。这是我尝试过的代码:
let newtags=[{key:1,text:'Sentence'}];
tagdata["Sentence"].map( (elem,x) => {
newtags.push({key:x,text:Object.keys(elem)[0],parent:x});
if(Object.keys(elem)[0].length !== 0){
var y=x+1;
newtags.push({key:y,text:Object.values(elem)[0][x],parent:y});
}
});
console.log(newtags);
答案 0 :(得分:2)
您的代码适用于第一级,但是当您尝试更深层次时,您将分配重复的键值(y=x+1
,当x
具有该值时.map()
方法的下一次迭代。
这里需要的是一个递归函数,它可以调用自己以与任何其他级别相同的方式处理嵌套级别。
您可以使用此ES6,函数式编程解决方案:
function listItems(obj) {
var key = 0;
return (function recurse(obj, parent = undefined) {
return Object(obj) !== obj ? { key: ++key, text: obj, parent }
: Array.isArray(obj) ? Object.keys(obj).reduce( (acc, text) =>
acc.concat(recurse(obj[text], parent)), [])
: Object.keys(obj).reduce( (acc, text) =>
acc.concat({ key: ++key, text, parent },
recurse(obj[text], key)), []);
})(obj);
}
// Sample data
var tagdata = {
"Sentence": [{
"NP": [{ "NMP": "cat" }, { "NMP": "dog" }]
}, {
"VP": [{
"KPD": "tree"
}, {
"NP": [{ "NMP": "ball" }, { "NMP": "bat" }]
},{
"NP": [{ "NMP": "ground" }, { "NMP": "time" }]
}]
}]
};
// Extract the objects and output:
console.log(listItems(tagdata));
.as-console-wrapper { max-height: 100% !important; top: 0; }
答案 1 :(得分:1)
我认为这可以满足您的需求。它使用递归算法来处理与具有对象的情况分开的数组的情况。只是一个字符串的基本情况在processChild
处理。
let state = [];
function processChild(child, parent) {
if (Array.isArray(child)) {
return processArray(child, parent);
}
if (typeof(child) == 'object') {
return processObject(child, parent);
}
let tag = {
key: state.length + 1,
text: child,
};
if (parent) {
tag.parent = parent;
}
state.push(tag);
}
function processObject(object, parent) {
parent = parent || 0;
let keys = Object.keys(object);
for (let i = 0; i < keys.length; i++) {
//console.log(keys[i]);
let tagIndex = state.length + 1;
let text = keys[i];
let tag = {
key: tagIndex,
text: text,
};
if (parent) {
tag.parent = parent;
}
state.push(tag);
let child = object[keys[i]];
processChild(child, tagIndex);
}
}
function processArray(array, parent) {
parent = parent || 0;
for (let i = 0; i < array.length; i++) {
//console.log(array[i]);
let child = array[i];
//console.log('Child', child);
processChild(child, parent);
}
}
function process(){
let initialState = JSON.parse(input.innerHTML);
processChild(initialState);
code.innerHTML = JSON.stringify(state).replace(/},/g,'},\n');
}
#input{
width: 100%;
height: 200px;
}
<textarea id="input">
{
"Sentence": [{
"NP": [{
"NMP": "cat"
}, {
"NMP": "dog"
}]
}, {
"VP": [{
"KPD": "tree"
}, {
"NP": [{
"NMP": "ball"
}, {
"NMP": "bat"
}]
}, {
"NP": [{
"NMP": "ground"
}, {
"NMP": "time"
}]
}]
}]
}
</textarea>
<button onClick="process()">Process</button>
<pre id="code"></pre>
答案 2 :(得分:1)
只是为了好玩,一种非递归的方式。
results
)todo
数组
var tagData = [{Sentence:[{NP:[{NMP:"cat"},{NMP:"dog"}]},{VP:[{KPD:"tree"},{NP:[{NMP:"ball"},{NMP:"bat"}]},{NP:[{NMP:"ground"},{NMP:"time"}]}]}]}];
var isNode = n => Array.isArray(n);
var isLeaf = n => !isNode(n);
var todoItem = parent => node => ({ parent, node });
var flatten = function(arr) {
var result = [],
todo = arr.map(todoItem(0)),
current, node, parent, key, innerNode;
while (todo.length) {
({node, parent} = todo.pop());
key = result.length + 1;
Object.keys(node).forEach(k => {
innerNode = node[k];
result.push({ key, parent, text: k });
if (isLeaf(innerNode)) {
result.push({
key: key + 1,
parent: key,
text: innerNode
});
} else {
todo = todo.concat(
innerNode.map(todoItem(key)));
}
});
};
return result;
};
// Print output
console.log(
flatten(tagData)
.map(o => [
"key: " + (o.key < 10 ? " " : "") + o.key,
"parent: " + (o.parent < 10 ? " " : "") + o.parent,
o.text
].join(" | "))
);
&#13;
.as-console-wrapper {
min-height: 100%;
}
&#13;