简体   繁体   English

如何遍历此嵌套对象?

[英]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. 只是为了好玩,一种非递归方法。

  • One array keeps track of the eventual results ( results ) 一个数组跟踪最终结果( results
  • One array keeps track of data-to-process 一个阵列跟踪数据到处理
  • When nested data is found, it is wrapped in a "to-do item" and added to the todo array 找到嵌套数据后,将其包装在“ todo ”中并添加到todo数组中
  • Repeat until no items left 重复直到没有剩余物品

 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM