[英]How to loop through this nested object?
I have a dynamically generated JavaScript object which consist of nested objects and arrays. 我有一个动态生成的JavaScript对象,该对象由嵌套对象和数组组成。 I couldn't find a proper way to list all nested objects, since that particular object is created dynamically. 我找不到列出所有嵌套对象的正确方法,因为该特定对象是动态创建的。
Here is the object: 这是对象:
var tagdata = {
"Sentence": [{
"NP": [{
"NMP": "cat"
}, {
"NMP": "dog"
}]
}, {
"VP": [{
"KPD": "tree"
}, {
"NP": [{
"NMP": "ball"
}, {
"NMP": "bat"
}]
},{
"NP": [{
"NMP": "ground"
}, {
"NMP": "time"
}]
}]
}]
};
The output I require looks like this: 我需要的输出如下所示:
[{ 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},]
This data is to be used in a tree, so the order might be different, but the key:parent relationship should be maintained. 该数据将在树中使用,因此顺序可能有所不同,但应保持key:parent关系。 Here is the code I've tried with: 这是我尝试过的代码:
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);
Your code works for the first level, but in your attempt to go one level deeper you will assign duplicate key values ( y=x+1
when x
will have that value in the next iteration of the .map()
method as well). 您的代码适用于第一级,但是如果尝试更深一层,您将分配重复的键值 (当x
在.map()
方法的下一次迭代中也具有该值时, y=x+1
)。
What you need here is a recursive function, one that calls itself to deal with nested levels in the same way as any other level. 这里您需要的是一个递归函数,该函数以与其他任何级别相同的方式调用自身以处理嵌套级别。
You could use this ES6, functional programming solution for that: 您可以为此使用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; }
I think this does what you want. 我认为这可以满足您的需求。 It uses a recursive algorithm that handles the case where you have an array separately from the case where you have an object. 它使用递归算法来处理数组和对象的情况。 The base case of just a string is handled in processChild
. 仅字符串的基本情况在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>
Just for fun, a non-recursive approach. 只是为了好玩,一种非递归方法。
results
) 一个数组跟踪最终结果( results
) todo
array 找到嵌套数据后,将其包装在“ todo
”中并添加到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(" | ")) );
.as-console-wrapper { min-height: 100%; }
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.